Home | History | Annotate | Line # | Download | only in test
harness.c revision 1.1.1.1
      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