1
0
mirror of git://sourceware.org/git/lvm2.git synced 2024-12-22 17:35:59 +03:00
lvm2/test/harness.c
Petr Rockai 15bd6a29b9 Revert the "repeat failed tests with -vvvv" feature. Instead, dump debug logs
to a file using log/file, with log/overwrite set and dump this file in
STACKTRACE. The overall effect is that only the command that ran last before
the failure has been triggered will get its debug output logged. This is
similar to how we treat coredumps.
2010-05-12 11:23:16 +00:00

202 lines
3.7 KiB
C

#include <fcntl.h>
#include <string.h>
#include <stdio.h>
#include <sys/socket.h>
#include <sys/wait.h>
#include <unistd.h>
#include <stdlib.h>
pid_t pid;
int fds[2];
#define MAX 1024
struct stats {
int nfailed;
int nskipped;
int npassed;
int nwarned;
int status[MAX];
};
struct stats s;
char *readbuf = NULL;
int readbuf_sz = 0, readbuf_used = 0;
int die = 0;
#define PASSED 0
#define SKIPPED 1
#define FAILED 2
#define WARNED 3
void handler( int s ) {
signal( s, SIG_DFL );
kill( pid, s );
die = s;
}
void dump() {
fwrite(readbuf, 1, readbuf_used, stdout);
}
void clear() {
readbuf_used = 0;
}
void drain() {
int sz;
char buf[2048];
while (1) {
sz = read(fds[1], buf, 2048);
if (sz <= 0)
return;
if (readbuf_used + sz >= readbuf_sz) {
readbuf_sz = readbuf_sz ? 2 * readbuf_sz : 4096;
readbuf = realloc(readbuf, readbuf_sz);
}
if (!readbuf)
exit(205);
memcpy(readbuf + readbuf_used, buf, sz);
readbuf_used += sz;
readbuf[readbuf_used] = 0;
}
}
void passed(int i, char *f) {
if (strstr(readbuf, "TEST WARNING")) {
++s.nwarned;
s.status[i] = WARNED;
printf("warnings\n");
} else {
++ s.npassed;
s.status[i] = PASSED;
printf("passed.\n");
}
}
void skipped(int i, char *f) {
++ s.nskipped;
s.status[i] = SKIPPED;
printf("skipped.\n");
}
void failed(int i, char *f, int st) {
++ s.nfailed;
s.status[i] = FAILED;
if(die == 2) {
printf("interrupted.\n");
return;
}
printf("FAILED.\n");
printf("-- FAILED %s ------------------------------------\n", f);
dump();
printf("-- FAILED %s (end) ------------------------------\n", f);
}
void run(int i, char *f) {
pid = fork();
if (pid < 0) {
perror("Fork failed.");
exit(201);
} else if (pid == 0) {
close(0);
dup2(fds[0], 1);
dup2(fds[0], 2);
execlp("bash", "bash", f, NULL);
perror("execlp");
fflush(stderr);
_exit(202);
} else {
char buf[128];
snprintf(buf, 128, "%s ...", f);
buf[127] = 0;
printf("Running %-40s ", buf);
fflush(stdout);
int st, w;
while ((w = waitpid(pid, &st, WNOHANG)) == 0) {
drain();
usleep(20000);
}
if (w != pid) {
perror("waitpid");
exit(206);
}
drain();
if (WIFEXITED(st)) {
if (WEXITSTATUS(st) == 0) {
passed(i, f);
} else if (WEXITSTATUS(st) == 200) {
skipped(i, f);
} else {
failed(i, f, st);
}
} else {
failed(i, f, st);
}
clear();
}
}
int main(int argc, char **argv) {
int i;
if (argc >= MAX) {
fprintf(stderr, "Sorry, my head exploded. Please increase MAX.\n");
exit(1);
}
s.nwarned = s.nfailed = s.npassed = s.nskipped = 0;
char *config = getenv("LVM_TEST_CONFIG"),
*config_debug;
config = config ? config : "";
asprintf(&config_debug, "%s\n%s\n", config, "log { verbose=4 }");
if (socketpair(PF_UNIX, SOCK_STREAM, 0, fds)) {
perror("socketpair");
return 201;
}
if ( fcntl( fds[1], F_SETFL, O_NONBLOCK ) == -1 ) {
perror("fcntl on socket");
return 202;
}
/* set up signal handlers */
for (i = 0; i <= 32; ++i) {
if (i == SIGCHLD || i == SIGWINCH || i == SIGURG)
continue;
signal(i, handler);
}
/* run the tests */
for (i = 1; i < argc; ++ i) {
run(i, argv[i]);
if (die)
break;
}
printf("\n## %d tests: %d OK, %d warnings, %d failures; %d skipped\n",
s.nwarned + s.npassed + s.nfailed + s.nskipped,
s.npassed, s.nwarned, s.nfailed, s.nskipped);
/* print out a summary */
if (s.nfailed || s.nskipped) {
for (i = 1; i < argc; ++ i) {
switch (s.status[i]) {
case FAILED:
printf("FAILED: %s\n", argv[i]);
break;
case SKIPPED:
printf("skipped: %s\n", argv[i]);
break;
}
}
printf("\n");
return s.nfailed > 0 || die;
}
return die;
}