import source from lvm2 2.02.79
[external/device-mapper.git] / test / harness.c
1 /*
2  * Copyright (C) 2010 Red Hat, Inc. All rights reserved.
3  *
4  * This file is part of LVM2.
5  *
6  * This copyrighted material is made available to anyone wishing to use,
7  * modify, copy, or redistribute it subject to the terms and conditions
8  * of the GNU General Public License v.2.
9  *
10  * You should have received a copy of the GNU General Public License
11  * along with this program; if not, write to the Free Software Foundation,
12  * Inc., 59 Temple Place, Suite 330, Boston, MA  02111-1307  USA
13  */
14
15 #include <fcntl.h>
16 #include <string.h>
17 #include <stdio.h>
18 #include <sys/socket.h>
19 #include <sys/wait.h>
20 #include <unistd.h>
21 #include <stdlib.h>
22
23 pid_t pid;
24 int fds[2];
25
26 #define MAX 1024
27
28 struct stats {
29         int nfailed;
30         int nskipped;
31         int npassed;
32         int nwarned;
33         int status[MAX];
34 };
35
36 struct stats s;
37
38 char *readbuf = NULL;
39 int readbuf_sz = 0, readbuf_used = 0;
40
41 int die = 0;
42 int verbose = 0;
43
44 #define PASSED 0
45 #define SKIPPED 1
46 #define FAILED 2
47 #define WARNED 3
48
49 void handler( int s ) {
50         signal( s, SIG_DFL );
51         kill( pid, s );
52         die = s;
53 }
54
55 void dump() {
56         fwrite(readbuf, 1, readbuf_used, stdout);
57 }
58
59 void clear() {
60         readbuf_used = 0;
61 }
62
63 void drain() {
64         int sz;
65         char buf[2048];
66         while (1) {
67                 sz = read(fds[1], buf, 2048);
68                 if (verbose)
69                         write(1, buf, sz);
70                 if (sz <= 0)
71                         return;
72                 if (readbuf_used + sz >= readbuf_sz) {
73                         readbuf_sz = readbuf_sz ? 2 * readbuf_sz : 4096;
74                         readbuf = realloc(readbuf, readbuf_sz);
75                 }
76                 if (!readbuf)
77                         exit(205);
78                 memcpy(readbuf + readbuf_used, buf, sz);
79                 readbuf_used += sz;
80                 readbuf[readbuf_used] = 0;
81         }
82 }
83
84 void passed(int i, char *f) {
85         if (strstr(readbuf, "TEST WARNING")) {
86                 ++s.nwarned;
87                 s.status[i] = WARNED;
88                 printf("warnings\n");
89         } else {
90                 ++ s.npassed;
91                 s.status[i] = PASSED;
92                 printf("passed.\n");
93         }
94 }
95
96 void skipped(int i, char *f) {
97         ++ s.nskipped;
98         s.status[i] = SKIPPED;
99         printf("skipped.\n");
100 }
101
102 void failed(int i, char *f, int st) {
103         ++ s.nfailed;
104         s.status[i] = FAILED;
105         if(die == 2) {
106                 printf("interrupted.\n");
107                 return;
108         }
109         printf("FAILED.\n");
110         printf("-- FAILED %s ------------------------------------\n", f);
111         dump();
112         printf("-- FAILED %s (end) ------------------------------\n", f);
113 }
114
115 void run(int i, char *f) {
116         pid = fork();
117         if (pid < 0) {
118                 perror("Fork failed.");
119                 exit(201);
120         } else if (pid == 0) {
121                 close(0);
122                 dup2(fds[0], 1);
123                 dup2(fds[0], 2);
124                 execlp("bash", "bash", f, NULL);
125                 perror("execlp");
126                 fflush(stderr);
127                 _exit(202);
128         } else {
129                 char buf[128];
130                 snprintf(buf, 128, "%s ...", f);
131                 buf[127] = 0;
132                 printf("Running %-40s ", buf);
133                 fflush(stdout);
134                 int st, w;
135                 while ((w = waitpid(pid, &st, WNOHANG)) == 0) {
136                         drain();
137                         usleep(20000);
138                 }
139                 if (w != pid) {
140                         perror("waitpid");
141                         exit(206);
142                 }
143                 drain();
144                 if (WIFEXITED(st)) {
145                         if (WEXITSTATUS(st) == 0) {
146                                 passed(i, f);
147                         } else if (WEXITSTATUS(st) == 200) {
148                                 skipped(i, f);
149                         } else {
150                                 failed(i, f, st);
151                         }
152                 } else {
153                         failed(i, f, st);
154                 }
155                 clear();
156         }
157 }
158
159 int main(int argc, char **argv) {
160         int i;
161
162         if (argc >= MAX) {
163                 fprintf(stderr, "Sorry, my head exploded. Please increase MAX.\n");
164                 exit(1);
165         }
166
167         s.nwarned = s.nfailed = s.npassed = s.nskipped = 0;
168
169         char *config = getenv("LVM_TEST_CONFIG"),
170                 *config_debug,
171                 *be_verbose = getenv("VERBOSE");
172         if (be_verbose && atoi(be_verbose))
173                 verbose = 1; // XXX
174         config = config ? config : "";
175         asprintf(&config_debug, "%s\n%s\n", config, "log { verbose=4 }");
176
177         if (socketpair(PF_UNIX, SOCK_STREAM, 0, fds)) {
178                 perror("socketpair");
179                 return 201;
180         }
181
182         if ( fcntl( fds[1], F_SETFL, O_NONBLOCK ) == -1 ) {
183                 perror("fcntl on socket");
184                 return 202;
185         }
186
187         /* set up signal handlers */
188         for (i = 0; i <= 32; ++i) {
189             if (i == SIGCHLD || i == SIGWINCH || i == SIGURG)
190                 continue;
191             signal(i, handler);
192         }
193
194         /* run the tests */
195         for (i = 1; i < argc; ++ i) {
196                 run(i, argv[i]);
197                 if (die)
198                         break;
199         }
200
201         printf("\n## %d tests: %d OK, %d warnings, %d failures; %d skipped\n",
202                s.nwarned + s.npassed + s.nfailed + s.nskipped,
203                s.npassed, s.nwarned, s.nfailed, s.nskipped);
204
205         /* print out a summary */
206         if (s.nfailed || s.nskipped) {
207                 for (i = 1; i < argc; ++ i) {
208                         switch (s.status[i]) {
209                         case FAILED:
210                                 printf("FAILED: %s\n", argv[i]);
211                                 break;
212                         case SKIPPED:
213                                 printf("skipped: %s\n", argv[i]);
214                                 break;
215                         }
216                 }
217                 printf("\n");
218                 return s.nfailed > 0 || die;
219         }
220         return die;
221 }