2009-02-12 22:54:45 +03:00
# 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 ] ;
2010-04-07 13:41:33 +04:00
# define MAX 1024
struct stats {
int nfailed ;
int nskipped ;
int npassed ;
2010-04-30 18:33:39 +04:00
int nwarned ;
2010-04-07 13:41:33 +04:00
int status [ MAX ] ;
} ;
struct stats s ;
struct stats backup ;
2009-02-12 22:54:45 +03:00
char * readbuf = NULL ;
int readbuf_sz = 0 , readbuf_used = 0 ;
int die = 0 ;
# define PASSED 0
# define SKIPPED 1
# define FAILED 2
2010-04-30 18:33:39 +04:00
# define WARNED 3
2009-02-12 22:54:45 +03:00
void handler ( int s ) {
signal ( s , SIG_DFL ) ;
kill ( pid , s ) ;
die = s ;
}
void dump ( ) {
2010-04-07 13:48:11 +04:00
fwrite ( readbuf , 1 , readbuf_used , stdout ) ;
2009-02-12 22:54:45 +03:00
}
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 ;
2010-04-30 18:33:39 +04:00
readbuf [ readbuf_used ] = 0 ;
2009-02-12 22:54:45 +03:00
}
}
void passed ( int i , char * f ) {
2010-04-30 18:33:39 +04:00
if ( strstr ( readbuf , " TEST WARNING " ) ) {
+ + s . nwarned ;
s . status [ i ] = WARNED ;
printf ( " warnings \n " ) ;
} else {
+ + s . npassed ;
s . status [ i ] = PASSED ;
printf ( " passed. \n " ) ;
}
2009-02-12 22:54:45 +03:00
}
void skipped ( int i , char * f ) {
2010-04-07 13:41:33 +04:00
+ + s . nskipped ;
s . status [ i ] = SKIPPED ;
2009-02-12 22:54:45 +03:00
printf ( " skipped. \n " ) ;
}
void failed ( int i , char * f , int st ) {
2010-04-07 13:41:33 +04:00
+ + s . nfailed ;
s . status [ i ] = FAILED ;
2009-02-12 22:54:45 +03:00
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 " ) ;
2009-07-14 01:26:41 +04:00
fflush ( stderr ) ;
_exit ( 202 ) ;
2009-02-12 22:54:45 +03:00
} 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 ) ;
}
2009-02-17 22:36:16 +03:00
drain ( ) ;
2009-02-12 22:54:45 +03:00
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 ;
2010-04-13 11:33:34 +04:00
int repeat = getenv ( " LVM_TEST_NOVERBOSE " ) ? 0 : 1 ;
2010-04-07 13:41:33 +04:00
if ( argc > = MAX ) {
fprintf ( stderr , " Sorry, my head exploded. Please increase MAX. \n " ) ;
exit ( 1 ) ;
}
2010-04-30 18:33:39 +04:00
s . nwarned = s . nfailed = s . npassed = s . nskipped = 0 ;
2010-04-07 13:41:33 +04:00
2010-04-01 02:18:17 +04:00
char * config = getenv ( " LVM_TEST_CONFIG " ) ,
* config_debug ;
2010-04-01 03:11:12 +04:00
config = config ? config : " " ;
asprintf ( & config_debug , " %s \n %s \n " , config , " log { verbose=4 } " ) ;
2009-02-12 22:54:45 +03:00
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 ;
2010-04-13 11:33:34 +04:00
if ( repeat & & s . status [ i ] = = FAILED ) {
2010-04-07 13:41:33 +04:00
backup = s ;
2010-04-01 02:18:17 +04:00
setenv ( " LVM_TEST_CONFIG " , config_debug , 1 ) ;
run ( i , argv [ i ] ) ;
setenv ( " LVM_TEST_CONFIG " , config , 1 ) ;
2010-04-07 13:41:33 +04:00
s = backup ;
2010-04-01 02:18:17 +04:00
}
2009-02-12 22:54:45 +03:00
}
2010-04-30 18:33:39 +04:00
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 ) ;
2009-02-12 22:54:45 +03:00
/* print out a summary */
2010-04-07 13:41:33 +04:00
if ( s . nfailed | | s . nskipped ) {
2009-02-12 22:54:45 +03:00
for ( i = 1 ; i < argc ; + + i ) {
2010-04-07 13:41:33 +04:00
switch ( s . status [ i ] ) {
2009-02-12 22:54:45 +03:00
case FAILED :
printf ( " FAILED: %s \n " , argv [ i ] ) ;
break ;
case SKIPPED :
printf ( " skipped: %s \n " , argv [ i ] ) ;
break ;
}
}
printf ( " \n " ) ;
2010-04-07 13:41:33 +04:00
return s . nfailed > 0 | | die ;
2009-02-12 22:54:45 +03:00
}
2010-04-13 11:34:19 +04:00
return die ;
2009-02-12 22:54:45 +03:00
}