1 /* $NetBSD: harness.c,v 1.1.1.1 2009/12/02 00:25:58 haad Exp $ */ 2 3 #include <fcntl.h> 4 #include <string.h> 5 #include <stdio.h> 6 #include <sys/socket.h> 7 #include <sys/wait.h> 8 #include <unistd.h> 9 #include <stdlib.h> 10 11 pid_t pid; 12 int fds[2]; 13 int *status; 14 int nfailed = 0; 15 int nskipped = 0; 16 int npassed = 0; 17 18 char *readbuf = NULL; 19 int readbuf_sz = 0, readbuf_used = 0; 20 21 int die = 0; 22 23 #define PASSED 0 24 #define SKIPPED 1 25 #define FAILED 2 26 27 void handler( int s ) { 28 signal( s, SIG_DFL ); 29 kill( pid, s ); 30 die = s; 31 } 32 33 void dump() { 34 write(1, readbuf, readbuf_used); 35 } 36 37 void clear() { 38 readbuf_used = 0; 39 } 40 41 void drain() { 42 int sz; 43 char buf[2048]; 44 while (1) { 45 sz = read(fds[1], buf, 2048); 46 if (sz <= 0) 47 return; 48 if (readbuf_used + sz >= readbuf_sz) { 49 readbuf_sz = readbuf_sz ? 2 * readbuf_sz : 4096; 50 readbuf = realloc(readbuf, readbuf_sz); 51 } 52 if (!readbuf) 53 exit(205); 54 memcpy(readbuf + readbuf_used, buf, sz); 55 readbuf_used += sz; 56 } 57 } 58 59 void passed(int i, char *f) { 60 ++ npassed; 61 status[i] = PASSED; 62 printf("passed.\n"); 63 } 64 65 void skipped(int i, char *f) { 66 ++ nskipped; 67 status[i] = SKIPPED; 68 printf("skipped.\n"); 69 } 70 71 void failed(int i, char *f, int st) { 72 ++ nfailed; 73 status[i] = FAILED; 74 if(die == 2) { 75 printf("interrupted.\n"); 76 return; 77 } 78 printf("FAILED.\n"); 79 printf("-- FAILED %s ------------------------------------\n", f); 80 dump(); 81 printf("-- FAILED %s (end) ------------------------------\n", f); 82 } 83 84 void run(int i, char *f) { 85 pid = fork(); 86 if (pid < 0) { 87 perror("Fork failed."); 88 exit(201); 89 } else if (pid == 0) { 90 close(0); 91 dup2(fds[0], 1); 92 dup2(fds[0], 2); 93 execlp("bash", "bash", f, NULL); 94 perror("execlp"); 95 fflush(stderr); 96 _exit(202); 97 } else { 98 char buf[128]; 99 snprintf(buf, 128, "%s ...", f); 100 buf[127] = 0; 101 printf("Running %-40s ", buf); 102 fflush(stdout); 103 int st, w; 104 while ((w = waitpid(pid, &st, WNOHANG)) == 0) { 105 drain(); 106 usleep(20000); 107 } 108 if (w != pid) { 109 perror("waitpid"); 110 exit(206); 111 } 112 drain(); 113 if (WIFEXITED(st)) { 114 if (WEXITSTATUS(st) == 0) { 115 passed(i, f); 116 } else if (WEXITSTATUS(st) == 200) { 117 skipped(i, f); 118 } else { 119 failed(i, f, st); 120 } 121 } else { 122 failed(i, f, st); 123 } 124 clear(); 125 } 126 } 127 128 int main(int argc, char **argv) { 129 int i; 130 status = alloca(sizeof(int)*argc); 131 132 if (socketpair(PF_UNIX, SOCK_STREAM, 0, fds)) { 133 perror("socketpair"); 134 return 201; 135 } 136 137 if ( fcntl( fds[1], F_SETFL, O_NONBLOCK ) == -1 ) { 138 perror("fcntl on socket"); 139 return 202; 140 } 141 142 /* set up signal handlers */ 143 for (i = 0; i <= 32; ++i) { 144 if (i == SIGCHLD || i == SIGWINCH || i == SIGURG) 145 continue; 146 signal(i, handler); 147 } 148 149 /* run the tests */ 150 for (i = 1; i < argc; ++ i) { 151 run(i, argv[i]); 152 if (die) 153 break; 154 } 155 156 printf("\n## %d tests: %d OK, %d failed, %d skipped\n", 157 npassed + nfailed + nskipped, npassed, nfailed, nskipped); 158 159 /* print out a summary */ 160 if (nfailed || nskipped) { 161 for (i = 1; i < argc; ++ i) { 162 switch (status[i]) { 163 case FAILED: 164 printf("FAILED: %s\n", argv[i]); 165 break; 166 case SKIPPED: 167 printf("skipped: %s\n", argv[i]); 168 break; 169 } 170 } 171 printf("\n"); 172 return nfailed > 0 || die; 173 } 174 return !die; 175 } 176