2006-10-17 00:05:19 +04:00
/*
Unix SMB / CIFS implementation .
Run subunit tests
Copyright ( C ) Jelmer Vernooij 2006
This program is free software ; you can redistribute it and / or modify
it under the terms of the GNU General Public License as published by
the Free Software Foundation ; either version 2 of the License , or
( at your option ) any later version .
This program is distributed in the hope that it will be useful ,
but WITHOUT ANY WARRANTY ; without even the implied warranty of
MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE . See the
GNU General Public License for more details .
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 . , 675 Mass Ave , Cambridge , MA 0213 9 , USA .
*/
# include "includes.h"
# include "system/dir.h"
# include "system/network.h"
# include "system/filesys.h"
# include "torture/ui.h"
2006-10-17 03:25:19 +04:00
# include "torture/torture.h"
2006-10-17 00:05:19 +04:00
# include "torture/proto.h"
2006-10-17 03:25:19 +04:00
struct torture_suite * torture_subunit_suite_create ( TALLOC_CTX * mem_ctx ,
const char * path )
2006-10-17 00:05:19 +04:00
{
2006-10-17 03:25:19 +04:00
struct torture_suite * suite = talloc_zero ( mem_ctx , struct torture_suite ) ;
2006-10-17 00:05:19 +04:00
suite - > path = talloc_strdup ( suite , path ) ;
suite - > name = talloc_strdup ( suite , strrchr ( path , ' / ' ) ? strrchr ( path , ' / ' ) + 1 :
path ) ;
suite - > description = talloc_asprintf ( suite , " Subunit test %s " , suite - > name ) ;
2006-10-17 03:25:19 +04:00
return suite ;
2006-10-17 00:05:19 +04:00
}
2006-10-17 03:25:19 +04:00
bool torture_subunit_load_testsuites ( const char * directory , bool recursive ,
struct torture_suite * parent )
2006-10-17 00:05:19 +04:00
{
DIR * dir ;
struct dirent * entry ;
char * filename ;
2006-10-17 03:25:19 +04:00
bool exists ;
if ( parent = = NULL )
parent = torture_root ;
2006-10-17 00:05:19 +04:00
dir = opendir ( directory ) ;
if ( dir = = NULL )
2006-10-17 03:25:19 +04:00
return true ;
2006-10-17 00:05:19 +04:00
while ( ( entry = readdir ( dir ) ) ) {
2006-10-17 03:25:19 +04:00
struct torture_suite * child ;
2006-10-17 04:56:29 +04:00
if ( entry - > d_name [ 0 ] = = ' . ' )
2006-10-17 00:05:19 +04:00
continue ;
2006-10-17 05:14:01 +04:00
filename = talloc_asprintf ( NULL , " %s/%s " , directory , entry - > d_name ) ;
if ( ! recursive & & directory_exist ( filename ) ) {
talloc_free ( filename ) ;
2006-10-17 03:25:19 +04:00
continue ;
2006-10-17 05:14:01 +04:00
}
2006-10-17 03:25:19 +04:00
2006-10-17 05:14:01 +04:00
if ( directory_exist ( filename ) ) {
2006-10-17 03:25:19 +04:00
child = torture_find_suite ( parent , entry - > d_name ) ;
exists = ( child ! = NULL ) ;
if ( child = = NULL )
child = torture_suite_create ( parent , entry - > d_name ) ;
torture_subunit_load_testsuites ( filename , true , child ) ;
} else {
child = torture_subunit_suite_create ( parent , filename ) ;
exists = false ;
}
if ( ! exists ) {
torture_suite_add_suite ( parent , child ) ;
2006-10-17 00:05:19 +04:00
}
talloc_free ( filename ) ;
}
closedir ( dir ) ;
2006-10-17 03:25:19 +04:00
return true ;
2006-10-17 00:05:19 +04:00
}
2006-10-18 20:47:35 +04:00
static pid_t piped_child ( char * const command [ ] , int * f_stdout , int * f_stderr )
2006-10-17 00:05:19 +04:00
{
pid_t pid ;
2006-10-18 20:47:35 +04:00
int sock_out [ 2 ] , sock_err [ 2 ] ;
2006-10-17 00:05:19 +04:00
2006-10-21 10:44:36 +04:00
if ( pipe ( sock_out ) = = - 1 ) {
2006-10-17 00:05:19 +04:00
DEBUG ( 0 , ( " socketpair: %s " , strerror ( errno ) ) ) ;
return - 1 ;
}
2006-10-21 10:44:36 +04:00
if ( pipe ( sock_err ) = = - 1 ) {
2006-10-18 20:47:35 +04:00
DEBUG ( 0 , ( " socketpair: %s " , strerror ( errno ) ) ) ;
return - 1 ;
}
* f_stdout = sock_out [ 0 ] ;
* f_stderr = sock_err [ 0 ] ;
2006-10-17 00:05:19 +04:00
pid = fork ( ) ;
if ( pid = = - 1 ) {
DEBUG ( 0 , ( " fork: %s " , strerror ( errno ) ) ) ;
return - 1 ;
}
if ( pid = = 0 ) {
close ( 0 ) ;
close ( 1 ) ;
close ( 2 ) ;
2006-10-18 20:47:35 +04:00
close ( sock_out [ 0 ] ) ;
close ( sock_err [ 0 ] ) ;
2006-10-17 00:05:19 +04:00
2006-10-21 10:44:36 +04:00
open ( " /dev/null " , O_RDONLY ) ;
2006-10-18 20:47:35 +04:00
dup2 ( sock_out [ 1 ] , 1 ) ;
dup2 ( sock_err [ 1 ] , 2 ) ;
2006-10-17 00:05:19 +04:00
execvp ( command [ 0 ] , command ) ;
exit ( - 1 ) ;
}
2006-10-18 20:47:35 +04:00
close ( sock_out [ 1 ] ) ;
close ( sock_err [ 1 ] ) ;
2006-10-17 00:05:19 +04:00
return pid ;
}
enum subunit_field { SUBUNIT_TEST , SUBUNIT_SUCCESS , SUBUNIT_FAILURE ,
SUBUNIT_SKIP } ;
static void run_subunit_message ( struct torture_context * context ,
enum subunit_field field ,
const char * name ,
const char * comment )
{
struct torture_test test ;
ZERO_STRUCT ( test ) ;
test . name = name ;
switch ( field ) {
case SUBUNIT_TEST :
2006-10-17 22:22:38 +04:00
test . description = comment ;
2006-10-17 00:05:19 +04:00
torture_ui_test_start ( context , NULL , & test ) ;
break ;
case SUBUNIT_FAILURE :
context - > active_test = & test ;
torture_ui_test_result ( context , TORTURE_FAIL , comment ) ;
context - > active_test = NULL ;
break ;
case SUBUNIT_SUCCESS :
context - > active_test = & test ;
torture_ui_test_result ( context , TORTURE_OK , comment ) ;
context - > active_test = NULL ;
break ;
case SUBUNIT_SKIP :
context - > active_test = & test ;
torture_ui_test_result ( context , TORTURE_SKIP , comment ) ;
context - > active_test = NULL ;
break ;
}
}
bool torture_subunit_run_suite ( struct torture_context * context ,
struct torture_suite * suite )
{
static char * command [ 2 ] ;
2006-10-18 20:47:35 +04:00
int fd_out , fd_err ;
2006-10-17 00:05:19 +04:00
pid_t pid ;
size_t size ;
char * p , * q ;
char * comment = NULL ;
char * name = NULL ;
enum subunit_field lastfield ;
int status ;
char buffer [ 4096 ] ;
size_t offset = 0 ;
2006-10-21 10:56:51 +04:00
2006-10-17 00:05:19 +04:00
command [ 0 ] = talloc_strdup ( context , suite - > path ) ;
command [ 1 ] = NULL ;
2006-10-18 20:47:35 +04:00
pid = piped_child ( command , & fd_out , & fd_err ) ;
2006-10-17 00:05:19 +04:00
if ( pid = = - 1 )
return false ;
2006-10-21 10:56:51 +04:00
while ( 1 ) {
fd_set fds ;
2006-10-17 00:05:19 +04:00
char * eol ;
2006-10-21 10:56:51 +04:00
FD_ZERO ( & fds ) ;
FD_SET ( fd_out , & fds ) ;
FD_SET ( fd_err , & fds ) ;
if ( select ( MAX ( fd_out , fd_err ) + 1 , & fds , NULL , NULL , NULL ) < = 0 ) break ;
if ( FD_ISSET ( fd_err , & fds ) ) {
size = read ( fd_err , buffer + offset , sizeof ( buffer ) - ( offset + 1 ) ) ;
if ( size < = 0 ) break ;
write ( 2 , buffer + offset , size ) ;
continue ;
}
if ( ! FD_ISSET ( fd_out , & fds ) ) continue ;
size = read ( fd_out , buffer + offset , sizeof ( buffer ) - ( offset + 1 ) ) ;
if ( size < = 0 ) break ;
2006-10-17 00:05:19 +04:00
buffer [ offset + size ] = ' \0 ' ;
2006-10-21 10:44:36 +04:00
write ( 1 , buffer + offset , size ) ;
2006-10-17 00:05:19 +04:00
for ( p = buffer ; p ; p = eol + 1 ) {
eol = strchr ( p , ' \n ' ) ;
if ( eol = = NULL )
break ;
* eol = ' \0 ' ;
if ( comment ! = NULL & & strcmp ( p , " ] " ) = = 0 ) {
run_subunit_message ( context , lastfield , name , comment ) ;
talloc_free ( name ) ; name = NULL ;
talloc_free ( comment ) ; comment = NULL ;
} else if ( comment ! = NULL ) {
comment = talloc_append_string ( context , comment , p ) ;
} else {
q = strchr ( p , ' : ' ) ;
if ( q = = NULL ) {
torture_comment ( context , " Invalid line `%s' \n " , p ) ;
continue ;
}
* q = ' \0 ' ;
if ( ! strcmp ( p , " test " ) ) {
lastfield = SUBUNIT_TEST ;
} else if ( ! strcmp ( p , " failure " ) ) {
lastfield = SUBUNIT_FAILURE ;
} else if ( ! strcmp ( p , " success " ) ) {
lastfield = SUBUNIT_SUCCESS ;
} else if ( ! strcmp ( p , " skip " ) ) {
lastfield = SUBUNIT_SKIP ;
} else {
torture_comment ( context , " Invalid subunit field `%s' \n " , p ) ;
continue ;
}
p = q + 1 ;
name = talloc_strdup ( context , p + 1 ) ;
q = strrchr ( p , ' [ ' ) ;
if ( q ! = NULL ) {
* q = ' \0 ' ;
comment = talloc_strdup ( context , " " ) ;
} else {
run_subunit_message ( context , lastfield , name , NULL ) ;
talloc_free ( name ) ;
name = NULL ;
}
}
}
2006-10-21 10:56:51 +04:00
2006-10-17 00:05:19 +04:00
offset + = size - ( p - buffer ) ;
memcpy ( buffer , p , offset ) ;
}
2006-10-21 10:44:36 +04:00
if ( waitpid ( pid , & status , 0 ) = = - 1 ) {
torture_result ( context , TORTURE_ERROR , " waitpid(%d) failed \n " , pid ) ;
return false ;
}
if ( WEXITSTATUS ( status ) ! = 0 ) {
torture_result ( context , TORTURE_ERROR , " failed with status %d \n " , WEXITSTATUS ( status ) ) ;
return false ;
}
2006-10-17 00:05:19 +04:00
if ( name ! = NULL ) {
2006-10-18 02:06:43 +04:00
torture_result ( context , TORTURE_ERROR , " Interrupted during %s \n " , name ) ;
2006-10-17 00:05:19 +04:00
return false ;
}
return true ;
}