-#include <ccan/failtest/failtest_override.h>
#include <ccan/oserver/oserver.c>
#include <ccan/oserver/oserver.h>
#include <ccan/str/str.h>
-#include <ccan/foreach/foreach.h>
#include <ccan/tap/tap.h>
#include <sys/types.h>
+#include <sys/select.h>
#include <sys/stat.h>
-#include <ccan/failtest/failtest.h>
#include <fcntl.h>
#include <string.h>
-#include <ccan/failtest/failtest_undo.h>
-static void exit_test(void)
+static void exit_quietly(struct tevent_context *ev,
+ struct tevent_fd *fde, uint16_t flags, void *unused)
{
- failtest_exit(exit_status());
+ talloc_free(ev);
+ exit(0);
+}
+
+static void run_server(int readyfd, int exitfd)
+{
+ struct tevent_context *ev = tevent_context_init(NULL);
+
+ if (oserver_setup(ev, OSERVER_PORT) == NULL)
+ exit(1);
+
+ /* Tell parent we are ready to go. */
+ write(readyfd, "", 1);
+
+ tevent_add_fd(ev, ev, exitfd, TEVENT_FD_READ, exit_quietly, NULL);
+ while (tevent_loop_wait(ev) == 0);
+}
+
+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;
+}
+
+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;
+}
+
+static bool no_input(int fd)
+{
+ fd_set set;
+ struct timeval t = { 0, 0 };
+
+ FD_ZERO(&set);
+ FD_SET(fd, &set);
+ return (select(fd+1, &set, NULL, NULL, &t) == 0);
}
int main(int argc, char *argv[])
{
- int fd;
- char buf[200];
- const char *input;
+ 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(3 * 6);
- failtest_init(argc, argv);
- tap_fail_callback = exit_test;
-
- foreach_ptr(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") {
- fd = open("run-fd", O_RDWR|O_CREAT|O_TRUNC, 0600);
-
- write(fd, input, strlen(input));
- lseek(fd, 0, SEEK_SET);
-
- ok1(oserver_serve(fd));
-
- lseek(fd, 0, SEEK_SET);
- buf[read(fd, buf, sizeof(buf)-1)] = '\0';
-
- ok1(strncmp(buf, input, strlen("This is a test")) == 0);
- ok1(streq(buf + strlen("This is a test") + 1,
- "Louder, like this: 'THIS IS A TEST'\r\n"));
+ 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 */
- failtest_exit(exit_status());
+ return exit_status();
}