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
handler(int s)27 void handler( int s ) {
28 signal( s, SIG_DFL );
29 kill( pid, s );
30 die = s;
31 }
32
dump()33 void dump() {
34 write(1, readbuf, readbuf_used);
35 }
36
clear()37 void clear() {
38 readbuf_used = 0;
39 }
40
drain()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
passed(int i,char * f)59 void passed(int i, char *f) {
60 ++ npassed;
61 status[i] = PASSED;
62 printf("passed.\n");
63 }
64
skipped(int i,char * f)65 void skipped(int i, char *f) {
66 ++ nskipped;
67 status[i] = SKIPPED;
68 printf("skipped.\n");
69 }
70
failed(int i,char * f,int st)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
run(int i,char * f)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
main(int argc,char ** argv)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