2010-07-28 16:20:38 +04:00
/*
2011-09-25 01:12:35 +04:00
* Copyright ( C ) 2010 - 2011 Red Hat , Inc . All rights reserved .
2010-07-28 16:20:38 +04:00
*
* This file is part of LVM2 .
*
* This copyrighted material is made available to anyone wishing to use ,
* modify , copy , or redistribute it subject to the terms and conditions
* of the GNU General Public License v .2 .
*
* You should have received a copy of the GNU General Public License
* along with this program ; if not , write to the Free Software Foundation ,
* Inc . , 59 Temple Place , Suite 330 , Boston , MA 02111 - 1307 USA
*/
2011-01-10 16:25:22 +03:00
# define _GNU_SOURCE
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>
2011-01-28 19:05:38 +03:00
# include <time.h>
2009-02-12 22:54:45 +03:00
2011-01-05 18:03:43 +03:00
static pid_t pid ;
static 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 ] ;
} ;
2011-01-05 18:03:43 +03:00
static struct stats s ;
2009-02-12 22:54:45 +03:00
2011-01-05 18:03:43 +03:00
static char * readbuf = NULL ;
static int readbuf_sz = 0 , readbuf_used = 0 ;
2009-02-12 22:54:45 +03:00
2011-01-05 18:03:43 +03:00
static int die = 0 ;
static int verbose = 0 ;
2011-01-05 03:16:18 +03:00
struct subst {
2011-03-10 17:47:22 +03:00
const char * key ;
char * value ;
2011-01-05 03:16:18 +03:00
} ;
2011-01-05 18:03:43 +03:00
static struct subst subst [ 2 ] ;
2009-02-12 22:54:45 +03:00
# 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
2011-01-13 14:02:55 +03:00
static void handler ( int sig ) {
signal ( sig , SIG_DFL ) ;
kill ( pid , sig ) ;
die = sig ;
2009-02-12 22:54:45 +03:00
}
2011-01-05 18:03:43 +03:00
static int outline ( char * buf , int start , int force ) {
2011-03-10 17:47:22 +03:00
char * from = buf + start ;
char * next = strchr ( buf + start , ' \n ' ) ;
if ( ! next & & ! force ) /* not a complete line yet... */
return start ;
if ( ! next )
next = from + strlen ( from ) ;
else
+ + next ;
if ( ! strncmp ( from , " @TESTDIR= " , 9 ) ) {
subst [ 0 ] . key = " @TESTDIR@ " ;
subst [ 0 ] . value = strndup ( from + 9 , next - from - 9 - 1 ) ;
} else if ( ! strncmp ( from , " @PREFIX= " , 8 ) ) {
subst [ 1 ] . key = " @PREFIX@ " ;
subst [ 1 ] . value = strndup ( from + 8 , next - from - 8 - 1 ) ;
} else {
char * line = strndup ( from , next - from ) ;
char * a = line , * b ;
do {
int idx = - 1 ;
int i ;
b = line + strlen ( line ) ;
for ( i = 0 ; i < 2 ; + + i ) {
if ( subst [ i ] . key ) {
// printf("trying: %s -> %s\n", subst[i].value, subst[i].key);
char * stop = strstr ( a , subst [ i ] . value ) ;
if ( stop & & stop < b ) {
idx = i ;
b = stop ;
}
}
}
fwrite ( a , 1 , b - a , stdout ) ;
a = b ;
if ( idx > = 0 ) {
fprintf ( stdout , " %s " , subst [ idx ] . key ) ;
a + = strlen ( subst [ idx ] . value ) ;
}
} while ( b < line + strlen ( line ) ) ;
free ( line ) ;
}
return next - buf + ( force ? 0 : 1 ) ;
2011-01-05 03:16:18 +03:00
}
2011-01-05 18:03:43 +03:00
static void dump ( void ) {
2011-01-13 18:03:28 +03:00
int counter_last = - 1 , counter = 0 ;
2011-01-05 03:16:18 +03:00
2011-01-13 14:02:55 +03:00
while ( counter < readbuf_used & & counter ! = counter_last ) {
counter_last = counter ;
counter = outline ( readbuf , counter , 1 ) ;
}
2009-02-12 22:54:45 +03:00
}
2011-01-05 18:03:43 +03:00
static void clear ( void ) {
2009-02-12 22:54:45 +03:00
readbuf_used = 0 ;
}
2011-01-05 18:03:43 +03:00
static void drain ( void ) {
2009-02-12 22:54:45 +03:00
int sz ;
char buf [ 2048 ] ;
2011-01-05 03:16:18 +03:00
2009-02-12 22:54:45 +03:00
while ( 1 ) {
2011-09-25 01:12:35 +04:00
sz = read ( fds [ 1 ] , buf , sizeof ( buf ) ) ;
2009-02-12 22:54:45 +03:00
if ( sz < = 0 )
return ;
2011-09-25 01:12:35 +04:00
if ( verbose )
write ( 1 , buf , sz ) ;
2009-02-12 22:54:45 +03:00
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
}
}
2011-01-28 19:05:38 +03:00
static const char * duration ( time_t start )
{
static char buf [ 16 ] ;
int t = ( int ) ( time ( NULL ) - start ) ;
sprintf ( buf , " %2d:%02d " , t / 60 , t % 60 ) ;
return buf ;
}
static void passed ( int i , char * f , time_t t ) {
2010-04-30 18:33:39 +04:00
if ( strstr ( readbuf , " TEST WARNING " ) ) {
+ + s . nwarned ;
s . status [ i ] = WARNED ;
2011-01-28 19:05:38 +03:00
printf ( " warnings %s \n " , duration ( t ) ) ;
2010-04-30 18:33:39 +04:00
} else {
+ + s . npassed ;
s . status [ i ] = PASSED ;
2011-01-28 19:05:38 +03:00
printf ( " passed. %s \n " , duration ( t ) ) ;
2010-04-30 18:33:39 +04:00
}
2009-02-12 22:54:45 +03:00
}
2011-01-05 18:03:43 +03:00
static 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 " ) ;
}
2011-01-05 18:03:43 +03:00
static 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 ) ;
}
2011-01-05 18:03:43 +03:00
static void run ( int i , char * f ) {
2009-02-12 22:54:45 +03:00
pid = fork ( ) ;
if ( pid < 0 ) {
perror ( " Fork failed. " ) ;
exit ( 201 ) ;
} else if ( pid = = 0 ) {
close ( 0 ) ;
dup2 ( fds [ 0 ] , 1 ) ;
dup2 ( fds [ 0 ] , 2 ) ;
2011-03-10 17:47:22 +03:00
close ( fds [ 0 ] ) ;
close ( fds [ 1 ] ) ;
2009-02-12 22:54:45 +03:00
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 {
2011-01-28 19:05:38 +03:00
int st , w ;
time_t start = time ( NULL ) ;
2009-02-12 22:54:45 +03:00
char buf [ 128 ] ;
snprintf ( buf , 128 , " %s ... " , f ) ;
buf [ 127 ] = 0 ;
printf ( " Running %-40s " , buf ) ;
fflush ( stdout ) ;
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 ) {
2011-01-28 19:05:38 +03:00
passed ( i , f , start ) ;
2009-02-12 22:54:45 +03:00
} 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 ) {
2011-01-28 19:05:38 +03:00
const char * be_verbose = getenv ( " VERBOSE " ) ;
time_t start = time ( NULL ) ;
2009-02-12 22:54:45 +03:00
int i ;
2010-04-07 13:41:33 +04:00
if ( argc > = MAX ) {
fprintf ( stderr , " Sorry, my head exploded. Please increase MAX. \n " ) ;
exit ( 1 ) ;
}
2010-10-14 18:36:26 +04:00
if ( be_verbose & & atoi ( be_verbose ) )
verbose = 1 ; // XXX
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 */
2011-03-10 17:47:22 +03:00
for ( i = 0 ; i < = 32 ; + + i ) {
if ( i = = SIGCHLD | | i = = SIGWINCH | | i = = SIGURG )
continue ;
signal ( i , handler ) ;
}
2009-02-12 22:54:45 +03:00
/* run the tests */
for ( i = 1 ; i < argc ; + + i ) {
run ( i , argv [ i ] ) ;
if ( die )
break ;
}
2011-01-28 19:05:38 +03:00
printf ( " \n ## %d tests %s : %d OK, %d warnings, %d failures; %d skipped \n " ,
2010-04-30 18:33:39 +04:00
s . nwarned + s . npassed + s . nfailed + s . nskipped ,
2011-01-28 19:05:38 +03:00
duration ( start ) ,
2010-04-30 18:33:39 +04:00
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
}
2011-01-28 19:05:38 +03:00
2011-09-25 01:12:35 +04:00
free ( readbuf ) ;
2010-04-13 11:34:19 +04:00
return die ;
2009-02-12 22:54:45 +03:00
}