]> git.ozlabs.org Git - ccan-lca-2011.git/blobdiff - ccan/oserver/test/run.c
lca2011: rewrite to a serious server
[ccan-lca-2011.git] / ccan / oserver / test / run.c
index f6c5b45762ff30a413fd840baaa1577e1321c671..f99e40bde103e57d511fd4830d916b24115e548a 100644 (file)
-#include <ccan/oserver/oserver.h>
 #include <ccan/oserver/oserver.c>
+#include <ccan/oserver/oserver.h>
 #include <ccan/str/str.h>
-#include <ccan/array_size/array_size.h>
 #include <ccan/tap/tap.h>
 #include <sys/types.h>
+#include <sys/select.h>
 #include <sys/stat.h>
 #include <fcntl.h>
 #include <string.h>
-#include <sys/wait.h>
 
-int main(void)
+static void exit_quietly(struct tevent_context *ev,
+                        struct tevent_fd *fde, uint16_t flags, void *unused)
 {
-       int fd, i;
-       int status;
-       char buf[200];
-       const char *input[] = { "This is a test\n",
-                               "This is a test\r",
-                               "This is a test\r\n",
-                               "This is a test\nWith extra",
-                               "This is a test\rWith extra",
-                               "This is a test\r\nWith extra" };
+       talloc_free(ev);
+       exit(0);
+}
 
-       /* This is how many tests you plan to run */
-       plan_tests(4 * ARRAY_SIZE(input));
+static void run_server(int readyfd, int exitfd)
+{
+       struct tevent_context *ev = tevent_context_init(NULL);
 
-       for (i = 0; i < ARRAY_SIZE(input); i++) {
-               fd = open("run-fd", O_RDWR|O_CREAT|O_TRUNC, 0600);
+       if (oserver_setup(ev, OSERVER_PORT) == NULL)
+               exit(1);
 
-               write(fd, input[i], strlen(input[i]));
-               lseek(fd, 0, SEEK_SET);
+       /* Tell parent we are ready to go. */
+       write(readyfd, "", 1);
 
-               if (fork() == 0)
-                       oserver_serve(fd);
+       tevent_add_fd(ev, ev, exitfd, TEVENT_FD_READ, exit_quietly, NULL);
+       while (tevent_loop_wait(ev) == 0);
+}      
 
-               wait(&status);
+static bool write_sall(int fd, const char *str)
+{
+       while (str[0]) {
+               ssize_t len = write(fd, str, strlen(str));
+               if (len < 0)
+                       return false;
+               str += len;
+       }
+       return true;
+}
 
-               ok1(WIFEXITED(status));
-               ok1(WEXITSTATUS(status) == 0);
+static bool input_is(int fd, const char *str)
+{
+       while (str[0]) {
+               char buffer[1000];
+               ssize_t len = read(fd, buffer, strlen(str));
+               if (len < 0)
+                       return false;
+               if (strncmp(str, buffer, len) != 0)
+                       return false;
+               str += len;
+       }
+       return true;
+}
 
-               lseek(fd, 0, SEEK_SET);
-               buf[read(fd, buf, sizeof(buf)-1)] = '\0';
+static bool no_input(int fd)
+{
+       fd_set set;
+       struct timeval t = { 0, 0 };
 
-               ok1(strncmp(buf, input[i], strlen("This is a test")) == 0);
-               ok1(streq(buf + strlen("This is a test") + 1,
-                         "Louder, like this: 'THIS IS A TEST'\r\n"));
+       FD_ZERO(&set);
+       FD_SET(fd, &set);
+       return (select(fd+1, &set, NULL, NULL, &t) == 0);
+}
+
+int main(int argc, char *argv[])
+{
+       int readyfd[2], exitfd[2];
+       union {
+               struct sockaddr addr;
+               struct sockaddr_in in;
+       } u;
+       int sfd1, sfd2;
+       char c;
+
+       /* This is how many tests you plan to run */
+       plan_tests(13);
+
+       pipe(readyfd);
+       pipe(exitfd);
+       if (fork() == 0) {
+               close(exitfd[1]);
+               close(readyfd[0]);
+               run_server(readyfd[1], exitfd[0]);
+               err(1, "Event loop failed");
        }
-               
+       close(exitfd[0]);
+       close(readyfd[1]);
+
+       sfd1 = socket(AF_INET, SOCK_STREAM, IPPROTO_TCP);
+       sfd2 = socket(AF_INET, SOCK_STREAM, IPPROTO_TCP);
+
+       u.in.sin_family = AF_INET;
+       u.in.sin_port = htons(OSERVER_PORT);
+       u.in.sin_addr.s_addr = htonl(INADDR_LOOPBACK);
+
+       /* Wait until child is ready... */
+       if (read(readyfd[0], &c, 1) != 1)
+               errx(1, "Child problems");
+
+       /* Go! */
+       ok1(connect(sfd1, &u.addr, sizeof(u.in)) == 0);
+       ok1(connect(sfd2, &u.addr, sizeof(u.in)) == 0);
+
+       ok1(write_sall(sfd1, "question"));
+       ok1(write_sall(sfd2, "question"));
+       /* It shouldn't say anything until we've finished! */
+       ok1(no_input(sfd1));
+       ok1(no_input(sfd2));
+
+       ok1(write_sall(sfd1, " 1\n"));
+       ok1(write_sall(sfd2, " 2\n"));
+
+       ok1(input_is(sfd1, "QUESTION 1\n"));
+       ok1(input_is(sfd2, "QUESTION 2\n"));
+
+       /* Sockets should be dead now. */
+       ok1(read(sfd1, &c, 1) == 0);
+       ok1(read(sfd2, &c, 1) == 0);
+
+       /* Shut down server. */
+       write(exitfd[1], "", 1);
+
+       /* This will close once it's shut down, and return. */
+       ok1(read(readyfd[0], &c, 1) == 0);
+
        /* This exits depending on whether all tests passed */
        return exit_status();
 }