ctdb-tests: Add comments describing sock daemon tests
[vlendec/samba-autobuild/.git] / ctdb / tests / src / sock_daemon_test.c
index 14ddefdb2e0b2676c9d012df132d942a1af2e737..98b9f066fc8af895201eab39ea0131f4e101b30a 100644 (file)
@@ -54,6 +54,12 @@ static struct sock_socket_funcs dummy_socket_funcs = {
        .read_recv = dummy_read_recv,
 };
 
+/*
+ * test1
+ *
+ * Check setup without actually running daemon
+ */
+
 static void test1(TALLOC_CTX *mem_ctx, const char *pidfile,
                  const char *sockpath)
 {
@@ -86,6 +92,13 @@ static void test1(TALLOC_CTX *mem_ctx, const char *pidfile,
        assert(ret == -1);
 }
 
+/*
+ * test2
+ *
+ * Start daemon, check PID file, sock daemon functions, termination,
+ * exit code
+ */
+
 static void test2_startup(void *private_data)
 {
        int fd = *(int *)private_data;
@@ -200,6 +213,12 @@ static void test2(TALLOC_CTX *mem_ctx, const char *pidfile,
        assert(ret == -1);
 }
 
+/*
+ * test3
+ *
+ * Start daemon, test watching of (parent) PID
+ */
+
 static void test3(TALLOC_CTX *mem_ctx, const char *pidfile,
                  const char *sockpath)
 {
@@ -254,17 +273,74 @@ static void test3(TALLOC_CTX *mem_ctx, const char *pidfile,
        assert(ret == -1);
 }
 
-static void test4_handler(struct tevent_context *ev,
-                         struct tevent_timer *te,
-                         struct timeval curtime,
-                         void *private_data)
+/*
+ * test4
+ *
+ * Start daemon, test termination via wait_send function
+ */
+
+struct test4_wait_state {
+};
+
+static void test4_wait_done(struct tevent_req *subreq);
+
+static struct tevent_req *test4_wait_send(TALLOC_CTX *mem_ctx,
+                                         struct tevent_context *ev,
+                                         void *private_data)
 {
-       struct sock_daemon_context *sockd = talloc_get_type_abort(
-               private_data, struct sock_daemon_context);
+       struct tevent_req *req, *subreq;
+       struct test4_wait_state *state;
 
-       talloc_free(sockd);
+       req = tevent_req_create(mem_ctx, &state, struct test4_wait_state);
+       if (req == NULL) {
+               return NULL;
+       }
+
+       subreq = tevent_wakeup_send(state, ev,
+                                   tevent_timeval_current_ofs(10,0));
+       if (tevent_req_nomem(subreq, req)) {
+               return tevent_req_post(req, ev);
+       }
+       tevent_req_set_callback(subreq, test4_wait_done, req);
+
+       return req;
+}
+
+static void test4_wait_done(struct tevent_req *subreq)
+{
+       struct tevent_req *req = tevent_req_callback_data(
+               subreq, struct tevent_req);
+       bool status;
+
+       status = tevent_wakeup_recv(subreq);
+       TALLOC_FREE(subreq);
+
+       if (! status) {
+               tevent_req_error(req, EIO);
+       } else {
+               tevent_req_done(req);
+       }
+}
+
+static bool test4_wait_recv(struct tevent_req *req, int *perr)
+{
+       int ret;
+
+       if (tevent_req_is_unix_error(req, &ret)) {
+               if (perr != NULL) {
+                       *perr = ret;
+               }
+               return false;
+       }
+
+       return true;
 }
 
+static struct sock_daemon_funcs test4_funcs = {
+       .wait_send = test4_wait_send,
+       .wait_recv = test4_wait_recv,
+};
+
 static void test4(TALLOC_CTX *mem_ctx, const char *pidfile,
                  const char *sockpath)
 {
@@ -278,19 +354,14 @@ static void test4(TALLOC_CTX *mem_ctx, const char *pidfile,
        if (pid == 0) {
                struct tevent_context *ev;
                struct sock_daemon_context *sockd;
-               struct tevent_timer *te;
 
                ev = tevent_context_init(mem_ctx);
                assert(ev != NULL);
 
                ret = sock_daemon_setup(mem_ctx, "test4", "file:", "NOTICE",
-                                       NULL, NULL, NULL, &sockd);
+                                       pidfile, &test4_funcs, NULL, &sockd);
                assert(ret == 0);
 
-               te = tevent_add_timer(ev, ev, tevent_timeval_current_ofs(10,0),
-                                     test4_handler, sockd);
-               assert(te != NULL);
-
                ret = sock_daemon_run(ev, sockd, -1);
                assert(ret == 0);
 
@@ -308,6 +379,12 @@ static void test4(TALLOC_CTX *mem_ctx, const char *pidfile,
        assert(ret == -1);
 }
 
+/*
+ * test5
+ *
+ * Start daemon, multiple client connects, requests, disconnects
+ */
+
 #define TEST5_MAX_CLIENTS      10
 
 struct test5_pkt {
@@ -606,27 +683,347 @@ static void test5(TALLOC_CTX *mem_ctx, const char *pidfile,
        assert(ret == 0);
 }
 
+/*
+ * test6
+ *
+ * Start daemon, test client connects, requests, replies, disconnects
+ */
+
+struct test6_pkt {
+       uint32_t len;
+       uint32_t data;
+};
+
+struct test6_client_state {
+       bool done;
+};
+
+static void test6_client_callback(uint8_t *buf, size_t buflen,
+                                 void *private_data)
+{
+       struct test6_client_state *state =
+               (struct test6_client_state *)private_data;
+       struct test6_pkt *pkt;
+
+       assert(buflen == sizeof(struct test6_pkt));
+       pkt = (struct test6_pkt *)buf;
+       assert(pkt->len == sizeof(struct test6_pkt));
+       assert(pkt->data == 0xffeeddcc);
+
+       state->done = true;
+}
+
+static void test6_client(const char *sockpath)
+{
+       struct tevent_context *ev;
+       struct test6_client_state state;
+       struct sock_queue *queue;
+       struct test6_pkt pkt;
+       int conn, ret;
+
+       ev = tevent_context_init(NULL);
+       assert(ev != NULL);
+
+       conn = sock_connect(sockpath);
+       assert(conn != -1);
+
+       state.done = false;
+
+       queue = sock_queue_setup(ev, ev, conn,
+                                test6_client_callback, &state);
+       assert(queue != NULL);
+
+       pkt.len = 8;
+       pkt.data = 0xaabbccdd;
+
+       ret = sock_queue_write(queue, (uint8_t *)&pkt,
+                              sizeof(struct test6_pkt));
+       assert(ret == 0);
+
+       while (! state.done) {
+               tevent_loop_once(ev);
+       }
+
+       talloc_free(ev);
+}
+
+struct test6_server_state {
+       struct sock_daemon_context *sockd;
+       int fd, done;
+};
+
+struct test6_read_state {
+       struct test6_server_state *server_state;
+       struct test6_pkt reply;
+};
+
+static void test6_read_done(struct tevent_req *subreq);
+
+static struct tevent_req *test6_read_send(TALLOC_CTX *mem_ctx,
+                                         struct tevent_context *ev,
+                                         struct sock_client_context *client,
+                                         uint8_t *buf, size_t buflen,
+                                         void *private_data)
+{
+       struct test6_server_state *server_state =
+               (struct test6_server_state *)private_data;
+       struct tevent_req *req, *subreq;
+       struct test6_read_state *state;
+       struct test6_pkt *pkt;
+
+       req = tevent_req_create(mem_ctx, &state, struct test6_read_state);
+       assert(req != NULL);
+
+       state->server_state = server_state;
+
+       assert(buflen == sizeof(struct test6_pkt));
+
+       pkt = (struct test6_pkt *)buf;
+       assert(pkt->data == 0xaabbccdd);
+
+       state->reply.len = sizeof(struct test6_pkt);
+       state->reply.data = 0xffeeddcc;
+
+       subreq = sock_socket_write_send(state, ev, client,
+                                       (uint8_t *)&state->reply,
+                                       state->reply.len);
+       assert(subreq != NULL);
+
+       tevent_req_set_callback(subreq, test6_read_done, req);
+
+       return req;
+}
+
+static void test6_read_done(struct tevent_req *subreq)
+{
+       struct tevent_req *req = tevent_req_callback_data(
+               subreq, struct tevent_req);
+       struct test6_read_state *state = tevent_req_data(
+               req, struct test6_read_state);
+       int ret;
+       bool status;
+
+       status = sock_socket_write_recv(subreq, &ret);
+       TALLOC_FREE(subreq);
+       if (! status) {
+               tevent_req_error(req, ret);
+               return;
+       }
+
+       state->server_state->done = 1;
+       tevent_req_done(req);
+}
+
+static bool test6_read_recv(struct tevent_req *req, int *perr)
+{
+       int ret;
+
+       if (tevent_req_is_unix_error(req, &ret)) {
+               if (perr != NULL) {
+                       *perr = ret;
+               }
+               return false;
+       }
+
+       return true;
+}
+
+static struct sock_socket_funcs test6_client_funcs = {
+       .read_send = test6_read_send,
+       .read_recv = test6_read_recv,
+};
+
+static void test6_startup(void *private_data)
+{
+       struct test6_server_state *server_state =
+               (struct test6_server_state *)private_data;
+       int ret = 1;
+       ssize_t nwritten;
+
+       nwritten = write(server_state->fd, &ret, sizeof(ret));
+       assert(nwritten == sizeof(ret));
+       close(server_state->fd);
+       server_state->fd = -1;
+}
+
+struct test6_wait_state {
+       struct test6_server_state *server_state;
+};
+
+static void test6_wait_done(struct tevent_req *subreq);
+
+static struct tevent_req *test6_wait_send(TALLOC_CTX *mem_ctx,
+                                         struct tevent_context *ev,
+                                         void *private_data)
+{
+       struct tevent_req *req, *subreq;
+       struct test6_wait_state *state;
+
+       req = tevent_req_create(mem_ctx, &state, struct test6_wait_state);
+       if (req == NULL) {
+               return NULL;
+       }
+
+       state->server_state = (struct test6_server_state *)private_data;
+
+       subreq = tevent_wakeup_send(state, ev,
+                                   tevent_timeval_current_ofs(10,0));
+       if (tevent_req_nomem(subreq, req)) {
+               return tevent_req_post(req, ev);
+       }
+       tevent_req_set_callback(subreq, test6_wait_done, req);
+
+       return req;
+}
+
+static void test6_wait_done(struct tevent_req *subreq)
+{
+       struct tevent_req *req = tevent_req_callback_data(
+               subreq, struct tevent_req);
+       struct test6_wait_state *state = tevent_req_data(
+               req, struct test6_wait_state);
+       bool status;
+
+       status = tevent_wakeup_recv(subreq);
+       TALLOC_FREE(subreq);
+       if (! status) {
+               tevent_req_error(req, EIO);
+               return;
+       }
+
+       if (state->server_state->done == 0) {
+               tevent_req_error(req, EIO);
+               return;
+       }
+
+       tevent_req_done(req);
+}
+
+static bool test6_wait_recv(struct tevent_req *req, int *perr)
+{
+       int ret;
+
+       if (tevent_req_is_unix_error(req, &ret)) {
+               if (perr != NULL) {
+                       *perr = ret;
+               }
+               return false;
+       }
+
+       return true;
+}
+
+static struct sock_daemon_funcs test6_funcs = {
+       .startup = test6_startup,
+       .wait_send = test6_wait_send,
+       .wait_recv = test6_wait_recv,
+};
+
+static void test6(TALLOC_CTX *mem_ctx, const char *pidfile,
+                 const char *sockpath)
+{
+       pid_t pid_server, pid;
+       int fd[2], ret;
+       ssize_t n;
+
+       pid = getpid();
+
+       ret = pipe(fd);
+       assert(ret == 0);
+
+       pid_server = fork();
+       assert(pid_server != -1);
+
+       if (pid_server == 0) {
+               struct tevent_context *ev;
+               struct sock_daemon_context *sockd;
+               struct test6_server_state server_state = { 0 };
+
+               close(fd[0]);
+
+               ev = tevent_context_init(mem_ctx);
+               assert(ev != NULL);
+
+               server_state.fd = fd[1];
+
+               ret = sock_daemon_setup(mem_ctx, "test6", "file:", "NOTICE",
+                                       pidfile, &test6_funcs, &server_state,
+                                       &sockd);
+               assert(ret == 0);
+
+               server_state.sockd = sockd;
+               server_state.done = 0;
+
+               ret = sock_daemon_add_unix(sockd, sockpath,
+                                          &test6_client_funcs, &server_state);
+               assert(ret == 0);
+
+               ret = sock_daemon_run(ev, sockd, pid);
+               assert(ret == 0);
+
+               exit(0);
+       }
+
+       close(fd[1]);
+
+       n = read(fd[0], &ret, sizeof(ret));
+       assert(n == sizeof(ret));
+       assert(ret == 1);
+
+       close(fd[0]);
+
+       test6_client(sockpath);
+
+       pid = wait(&ret);
+       assert(pid != -1);
+}
+
 int main(int argc, const char **argv)
 {
        TALLOC_CTX *mem_ctx;
        const char *pidfile, *sockpath;
+       int num;
 
-       if (argc != 3) {
-               fprintf(stderr, "%s <pidfile> <sockpath>\n", argv[0]);
+       if (argc != 4) {
+               fprintf(stderr, "%s <pidfile> <sockpath> <testnum>\n", argv[0]);
                exit(1);
        }
 
        pidfile = argv[1];
        sockpath = argv[2];
+       num = atoi(argv[3]);
 
        mem_ctx = talloc_new(NULL);
        assert(mem_ctx != NULL);
 
-       test1(mem_ctx, pidfile, sockpath);
-       test2(mem_ctx, pidfile, sockpath);
-       test3(mem_ctx, pidfile, sockpath);
-       test4(mem_ctx, pidfile, sockpath);
-       test5(mem_ctx, pidfile, sockpath);
+       switch (num) {
+       case 1:
+               test1(mem_ctx, pidfile, sockpath);
+               break;
+
+       case 2:
+               test2(mem_ctx, pidfile, sockpath);
+               break;
+
+       case 3:
+               test3(mem_ctx, pidfile, sockpath);
+               break;
+
+       case 4:
+               test4(mem_ctx, pidfile, sockpath);
+               break;
+
+       case 5:
+               test5(mem_ctx, pidfile, sockpath);
+               break;
+
+       case 6:
+               test6(mem_ctx, pidfile, sockpath);
+               break;
+
+       default:
+               fprintf(stderr, "Unknown test number %d\n", num);
+       }
 
        return 0;
 }