tests: Test portability
authorMathieu Parent <math.parent@gmail.com>
Mon, 14 Jan 2013 16:21:01 +0000 (17:21 +0100)
committerAmitay Isaacs <amitay@gmail.com>
Tue, 22 Jan 2013 07:03:47 +0000 (18:03 +1100)
Curiously test_ctdb_sys_check_iface_exists fails on Linux

Signed-off-by: Mathieu Parent <math.parent@gmail.com>
(This used to be ctdb commit 109f428aa34f8f4cc0329880d2f4a5593a6cc6f3)

ctdb/Makefile.in
ctdb/tests/src/ctdb_porting_tests.c [new file with mode: 0644]

index 5871557889a25528c1cd734c7090b8e74d7b53d3..e704d631bd7745795734a1d713434180c171f6b5 100755 (executable)
@@ -104,6 +104,7 @@ TEST_BINS=tests/bin/ctdb_bench tests/bin/ctdb_fetch tests/bin/ctdb_fetch_one \
        tests/bin/ctdb_takeover_tests tests/bin/ctdb_update_record \
        tests/bin/ctdb_update_record_persistent \
        tests/bin/ctdb_tool_libctdb tests/bin/ctdb_tool_stubby \
+       tests/bin/ctdb_porting_tests \
        @INFINIBAND_BINS@
 
 BINS = bin/ctdb @CTDB_SCSI_IO@ bin/smnotify bin/ping_pong bin/ltdbtool @CTDB_PMDA@
@@ -257,6 +258,10 @@ tests/bin/ctdb_persistent: $(CTDB_CLIENT_OBJ) tests/src/ctdb_persistent.o
        @echo Linking $@
        @$(CC) $(CFLAGS) -o $@ tests/src/ctdb_persistent.o $(CTDB_CLIENT_OBJ) $(LIB_FLAGS)
 
+tests/bin/ctdb_porting_tests: $(CTDB_CLIENT_OBJ) tests/src/ctdb_porting_tests.o
+       @echo Linking $@
+       $(CC) $(CFLAGS) -o $@ tests/src/ctdb_porting_tests.o $(CTDB_CLIENT_OBJ) $(LIB_FLAGS)
+
 tests/bin/ctdb_transaction: $(CTDB_CLIENT_OBJ) tests/src/ctdb_transaction.o 
        @echo Linking $@
        @$(CC) $(CFLAGS) -o $@ tests/src/ctdb_transaction.o $(CTDB_CLIENT_OBJ) $(LIB_FLAGS)
diff --git a/ctdb/tests/src/ctdb_porting_tests.c b/ctdb/tests/src/ctdb_porting_tests.c
new file mode 100644 (file)
index 0000000..0c43451
--- /dev/null
@@ -0,0 +1,305 @@
+/*
+   Test porting lib (common/system_*.c)
+
+   Copyright (C) Mathieu Parent 2013
+
+   This program is free software; you can redistribute it and/or modify
+   it under the terms of the GNU General Public License as published by
+   the Free Software Foundation; either version 3 of the License, or
+   (at your option) any later version.
+
+   This program 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 General Public License for more details.
+
+   You should have received a copy of the GNU General Public License
+   along with this program; if not, see <http://www.gnu.org/licenses/>.
+*/
+
+#include "includes.h"
+#include "include/ctdb_private.h"
+#include "system/filesys.h"
+#include "popt.h"
+#include "cmdline.h"
+
+static struct {
+       const char *socketname;
+       const char *debuglevel;
+       pid_t helper_pid;
+       int socket;
+       int successcount;
+       int testcount;
+} globals = {
+       .socketname = "/tmp/test.sock"
+};
+
+
+
+/*
+  Socket functions
+*/
+/*
+  create a unix domain socket and bind it
+  return a file descriptor open on the socket
+*/
+static int socket_server_create(void)
+{
+       struct sockaddr_un addr;
+
+       globals.socket = socket(AF_UNIX, SOCK_STREAM, 0);
+       if (globals.socket == -1) {
+               DEBUG(DEBUG_CRIT,("Unable to create server socket: %s\n", strerror(errno)));
+               return -1;
+       }
+
+       set_close_on_exec(globals.socket);
+       //set_nonblocking(globals.socket);
+
+       memset(&addr, 0, sizeof(addr));
+       addr.sun_family = AF_UNIX;
+       strncpy(addr.sun_path, globals.socketname, sizeof(addr.sun_path));
+
+       if (bind(globals.socket, (struct sockaddr *)&addr, sizeof(addr)) == -1) {
+               DEBUG(DEBUG_CRIT,("Unable to bind on socket '%s': %s\n", globals.socketname, strerror(errno)));
+               goto failed;
+       }
+
+       if (chown(globals.socketname, geteuid(), getegid()) != 0 ||
+               chmod(globals.socketname, 0700) != 0) {
+               DEBUG(DEBUG_CRIT,("Unable to secure socket '%s': %s\n", globals.socketname, strerror(errno)));
+               goto failed;
+       }
+
+
+       if (listen(globals.socket, 100) != 0) {
+               DEBUG(DEBUG_CRIT,("Unable to listen on socket '%s': %s\n", globals.socketname, strerror(errno)));
+               goto failed;
+       }
+       return 0;
+
+failed:
+       close(globals.socket);
+       globals.socket = -1;
+       return -1;
+}
+
+static int socket_server_wait_peer(void)
+{
+       struct sockaddr_un addr;
+       socklen_t len;
+       int fd;
+
+       memset(&addr, 0, sizeof(addr));
+       len = sizeof(addr);
+       fd = accept(globals.socket, (struct sockaddr *)&addr, &len);
+       if (fd == -1) {
+               DEBUG(DEBUG_CRIT,("Unable to accept on ctdb socket '%s': %s\n", globals.socketname, strerror(errno)));
+               return -1;
+       }
+
+       //set_nonblocking(fd);
+       set_close_on_exec(fd);
+       return fd;
+}
+
+static int socket_server_close(void)
+{
+       if (close(globals.socket) == -1) {
+               DEBUG(DEBUG_CRIT,("Unable to close server socket: %s\n", strerror(errno)));
+               return -1;
+       }
+       if (unlink(globals.socketname) == -1) {
+               DEBUG(DEBUG_CRIT,("Unable to remove server socket: %s\n", strerror(errno)));
+               return -1;
+       }
+       return 0;
+}
+
+static int socket_client_connect(void)
+{
+       struct sockaddr_un addr;
+       int client = 0;
+
+       client = socket(AF_UNIX, SOCK_STREAM, 0);
+       if (client == -1) {
+               DEBUG(DEBUG_CRIT,("Unable to create client socket: %s\n", strerror(errno)));
+               return -1;
+       }
+
+       memset(&addr, 0, sizeof(addr));
+       addr.sun_family = AF_UNIX;
+       strncpy(addr.sun_path, globals.socketname, sizeof(addr.sun_path));
+       if (connect(client, (struct sockaddr *)&addr, sizeof(addr))==-1) {
+               DEBUG(DEBUG_CRIT,("Unable to connect to '%s': %s\n", globals.socketname, strerror(errno)));
+               close(client);
+               return -1;
+       }
+
+       return client;
+}
+
+static int socket_client_write(int client)
+{
+       if (write(client, "\0", 1) == -1) {
+               DEBUG(DEBUG_CRIT,("Unable to write to client socket: %s\n", strerror(errno)));
+               return -1;
+       }
+       return 0;
+}
+
+static int socket_client_close(int client)
+{
+       if (close(client) == -1) {
+               DEBUG(DEBUG_CRIT,("Unable to close client socket: %s\n", strerror(errno)));
+               return -1;
+       }
+       return 0;
+}
+
+/*
+  forked program
+*/
+static int fork_helper(void)
+{
+       pid_t pid;
+       int i, client, max_rounds = 10;
+
+       pid = fork();
+       if (pid == -1) {
+               DEBUG(DEBUG_CRIT,("Unable to fork: %s\n", strerror(errno)));
+               return -1;
+       }
+       if (pid == 0) { // Child
+               client = socket_client_connect();
+               socket_client_write(client);
+               for (i = 1 ; i <= max_rounds ; i++ ) {
+                       DEBUG(DEBUG_DEBUG,("Child process waiting ( %d/%d)\n", i, max_rounds));
+                       sleep(1);
+               }
+               socket_client_close(client);
+               exit(0);
+       } else {
+               globals.helper_pid = pid;
+       }
+       return 0;
+}
+
+/*
+  tests
+*/
+int test_ctdb_sys_check_iface_exists(void)
+{
+       const char *fakename;
+       bool test;
+       globals.testcount++;
+       fakename = strdup("fake");
+       if (fakename == NULL) {
+               DEBUG(DEBUG_CRIT,("Unable to allocate memory\n"));
+               return -1;
+       }
+       test = ctdb_sys_check_iface_exists(fakename);
+       if(test == true) {
+               DEBUG(DEBUG_CRIT,("Test failed: Fake interface detected: %s\n", fakename));
+               return -1;
+       }
+       DEBUG(DEBUG_INFO,("Test OK: Fake interface not detected: %s\n", fakename));
+       globals.successcount++;
+       return 0;
+}
+
+int test_ctdb_get_peer_pid(void)
+{
+       int ret;
+       int fd;
+       pid_t peer_pid = 0;
+       globals.testcount++;
+       fd = socket_server_wait_peer();
+       ret = ctdb_get_peer_pid(fd, &peer_pid);
+       if (ret == -1) {
+               DEBUG(DEBUG_CRIT,("Test failed: Unable to get peer process id\n"));
+               return -1;
+       }
+       if (peer_pid <= 0) {
+               DEBUG(DEBUG_CRIT,("Test failed: Invalid peer process id: %d\n", peer_pid));
+               return -1;
+       }
+       DEBUG(DEBUG_INFO,("Test OK: Peer process id: %d\n", peer_pid));
+       globals.successcount++;
+       return 0;
+}
+
+int test_ctdb_get_process_name(void)
+{
+       char *process_name = NULL;
+       globals.testcount++;
+       process_name = ctdb_get_process_name(globals.helper_pid);
+       if ((process_name == NULL) || !strcmp(process_name, "unknown")) {
+               DEBUG(DEBUG_CRIT,("Test failed: Invalid process name of %d: %s\n", globals.helper_pid, process_name));
+               return -1;
+       }
+       DEBUG(DEBUG_INFO,("Test OK: Name of PID=%d: %s\n", globals.helper_pid, process_name));
+       globals.successcount++;
+       return 0;
+}
+
+/*
+  main program
+*/
+int main(int argc, const char *argv[])
+{
+       struct poptOption popt_options[] = {
+               POPT_AUTOHELP
+               { "socket", 0, POPT_ARG_STRING, &globals.socketname, 0, "local socket name", "filename" },
+               POPT_TABLEEND
+       };
+       int opt;
+       const char **extra_argv;
+       int extra_argc = 0;
+       poptContext pc;
+
+       LogLevel = DEBUG_INFO;
+
+       pc = poptGetContext(argv[0], argc, argv, popt_options, POPT_CONTEXT_KEEP_FIRST);
+
+       while ((opt = poptGetNextOpt(pc)) != -1) {
+               switch (opt) {
+               default:
+                       fprintf(stderr, "Invalid option %s: %s\n",
+                               poptBadOption(pc, 0), poptStrerror(opt));
+                       exit(1);
+               }
+       }
+
+       /* setup the remaining options for the main program to use */
+       extra_argv = poptGetArgs(pc);
+       if (extra_argv) {
+               extra_argv++;
+               while (extra_argv[extra_argc]) extra_argc++;
+       }
+
+       if (globals.socketname == NULL) {
+               DEBUG(DEBUG_CRIT,("Socket name is undefined\n"));
+               exit(1);
+       }
+       if (socket_server_create()) {
+               DEBUG(DEBUG_CRIT,("Socket error: exiting\n"));
+               exit(1);
+       }
+       if (fork_helper()) {
+               DEBUG(DEBUG_CRIT,("Forking error: exiting\n"));
+               exit(1);
+       }
+       /* FIXME: Test tcp_checksum6, tcp_checksum */
+       /* FIXME: Test ctdb_sys_send_arp, ctdb_sys_send_tcp */
+       /* FIXME: Test ctdb_sys_{open,close}_capture_socket, ctdb_sys_read_tcp_packet */
+       test_ctdb_sys_check_iface_exists();
+       test_ctdb_get_peer_pid();
+       test_ctdb_get_process_name();
+       /* FIXME: Test ctdb_get_lock_info, ctdb_get_blocker_pid*/
+
+       socket_server_close();
+
+       DEBUG(DEBUG_INFO,("%d/%d tests successfull\n", globals.successcount, globals.testcount));
+       return 0;
+}