@ -6,9 +6,28 @@
# include <assert.h>
# include <unistd.h>
# include <signal.h>
# include <errno.h>
# include "hiredis.h"
enum connection_type {
CONN_TCP ,
CONN_UNIX
} ;
struct config {
enum connection_type type ;
struct {
const char * host ;
int port ;
} tcp ;
struct {
const char * path ;
} unix ;
} ;
/* The following lines make up our testing "framework" :) */
static int tests = 0 , fails = 0 ;
# define test(_s) { printf("#%02d ", ++tests); printf(_s); }
@ -20,18 +39,63 @@ static long long usec(void) {
return ( ( ( long long ) tv . tv_sec ) * 1000000 ) + tv . tv_usec ;
}
static int use_unix = 0 ;
static redisContext * blocking_context = NULL ;
static void __connect ( redisContext * * target ) {
* target = blocking_context = ( use_unix ?
redisConnectUnix ( " /tmp/redis.sock " ) : redisConnect ( ( char * ) " 127.0.0.1 " , 6379 ) ) ;
if ( blocking_context - > err ) {
printf ( " Connection error: %s \n " , blocking_context - > errstr ) ;
static redisContext * select_database ( redisContext * c ) {
redisReply * reply ;
/* Switch to DB 9 for testing, now that we know we can chat. */
reply = redisCommand ( c , " SELECT 9 " ) ;
assert ( reply ! = NULL ) ;
freeReplyObject ( reply ) ;
/* Make sure the DB is emtpy */
reply = redisCommand ( c , " DBSIZE " ) ;
assert ( reply ! = NULL ) ;
if ( reply - > type = = REDIS_REPLY_INTEGER & & reply - > integer = = 0 ) {
/* Awesome, DB 9 is empty and we can continue. */
freeReplyObject ( reply ) ;
} else {
printf ( " Database #9 is not empty, test can not continue \n " ) ;
exit ( 1 ) ;
}
return c ;
}
static void disconnect ( redisContext * c ) {
redisReply * reply ;
/* Make sure we're on DB 9. */
reply = redisCommand ( c , " SELECT 9 " ) ;
assert ( reply ! = NULL ) ;
freeReplyObject ( reply ) ;
reply = redisCommand ( c , " FLUSHDB " ) ;
assert ( reply ! = NULL ) ;
freeReplyObject ( reply ) ;
/* Free the context as well. */
redisFree ( c ) ;
}
static redisContext * connect ( struct config config ) {
redisContext * c ;
if ( config . type = = CONN_TCP ) {
c = redisConnect ( config . tcp . host , config . tcp . port ) ;
} else if ( config . type = = CONN_UNIX ) {
c = redisConnectUnix ( config . unix . path ) ;
} else {
assert ( NULL ) ;
}
if ( c - > err ) {
printf ( " Connection error: %s \n " , c - > errstr ) ;
exit ( 1 ) ;
}
return select_database ( c ) ;
}
static void test_format_commands ( ) {
static void test_format_commands ( void ) {
char * cmd ;
int len ;
@ -53,6 +117,12 @@ static void test_format_commands() {
len = = 4 + 4 + ( 3 + 2 ) + 4 + ( 3 + 2 ) + 4 + ( 0 + 2 ) ) ;
free ( cmd ) ;
test ( " Format command with an empty string in between proper interpolations: " ) ;
len = redisFormatCommand ( & cmd , " SET %s %s " , " " , " foo " ) ;
test_cond ( strncmp ( cmd , " *3 \r \n $3 \r \n SET \r \n $0 \r \n \r \n $3 \r \n foo \r \n " , len ) = = 0 & &
len = = 4 + 4 + ( 3 + 2 ) + 4 + ( 0 + 2 ) + 4 + ( 3 + 2 ) ) ;
free ( cmd ) ;
test ( " Format command with %%b string interpolation: " ) ;
len = redisFormatCommand ( & cmd , " SET %b %b " , " foo " , 3 , " b \0 r " , 3 ) ;
test_cond ( strncmp ( cmd , " *3 \r \n $3 \r \n SET \r \n $3 \r \n foo \r \n $3 \r \n b \0 r \r \n " , len ) = = 0 & &
@ -115,10 +185,176 @@ static void test_format_commands() {
free ( cmd ) ;
}
static void test_blocking_connection ( ) {
static void test_reply_reader ( void ) {
redisReader * reader ;
void * reply ;
int ret ;
test ( " Error handling in reply parser: " ) ;
reader = redisReaderCreate ( ) ;
redisReaderFeed ( reader , ( char * ) " @foo \r \n " , 6 ) ;
ret = redisReaderGetReply ( reader , NULL ) ;
test_cond ( ret = = REDIS_ERR & &
strcasecmp ( reader - > errstr , " Protocol error, got \" @ \" as reply type byte " ) = = 0 ) ;
redisReaderFree ( reader ) ;
/* when the reply already contains multiple items, they must be free'd
* on an error . valgrind will bark when this doesn ' t happen . */
test ( " Memory cleanup in reply parser: " ) ;
reader = redisReaderCreate ( ) ;
redisReaderFeed ( reader , ( char * ) " *2 \r \n " , 4 ) ;
redisReaderFeed ( reader , ( char * ) " $5 \r \n hello \r \n " , 11 ) ;
redisReaderFeed ( reader , ( char * ) " @foo \r \n " , 6 ) ;
ret = redisReaderGetReply ( reader , NULL ) ;
test_cond ( ret = = REDIS_ERR & &
strcasecmp ( reader - > errstr , " Protocol error, got \" @ \" as reply type byte " ) = = 0 ) ;
redisReaderFree ( reader ) ;
test ( " Set error on nested multi bulks with depth > 1: " ) ;
reader = redisReaderCreate ( ) ;
redisReaderFeed ( reader , ( char * ) " *1 \r \n " , 4 ) ;
redisReaderFeed ( reader , ( char * ) " *1 \r \n " , 4 ) ;
redisReaderFeed ( reader , ( char * ) " *1 \r \n " , 4 ) ;
ret = redisReaderGetReply ( reader , NULL ) ;
test_cond ( ret = = REDIS_ERR & &
strncasecmp ( reader - > errstr , " No support for " , 14 ) = = 0 ) ;
redisReaderFree ( reader ) ;
test ( " Works with NULL functions for reply: " ) ;
reader = redisReaderCreate ( ) ;
reader - > fn = NULL ;
redisReaderFeed ( reader , ( char * ) " +OK \r \n " , 5 ) ;
ret = redisReaderGetReply ( reader , & reply ) ;
test_cond ( ret = = REDIS_OK & & reply = = ( void * ) REDIS_REPLY_STATUS ) ;
redisReaderFree ( reader ) ;
test ( " Works when a single newline ( \\ r \\ n) covers two calls to feed: " ) ;
reader = redisReaderCreate ( ) ;
reader - > fn = NULL ;
redisReaderFeed ( reader , ( char * ) " +OK \r " , 4 ) ;
ret = redisReaderGetReply ( reader , & reply ) ;
assert ( ret = = REDIS_OK & & reply = = NULL ) ;
redisReaderFeed ( reader , ( char * ) " \n " , 1 ) ;
ret = redisReaderGetReply ( reader , & reply ) ;
test_cond ( ret = = REDIS_OK & & reply = = ( void * ) REDIS_REPLY_STATUS ) ;
redisReaderFree ( reader ) ;
test ( " Don't reset state after protocol error: " ) ;
reader = redisReaderCreate ( ) ;
reader - > fn = NULL ;
redisReaderFeed ( reader , ( char * ) " x " , 1 ) ;
ret = redisReaderGetReply ( reader , & reply ) ;
assert ( ret = = REDIS_ERR ) ;
ret = redisReaderGetReply ( reader , & reply ) ;
test_cond ( ret = = REDIS_ERR & & reply = = NULL ) ;
redisReaderFree ( reader ) ;
/* Regression test for issue #45 on GitHub. */
test ( " Don't do empty allocation for empty multi bulk: " ) ;
reader = redisReaderCreate ( ) ;
redisReaderFeed ( reader , ( char * ) " *0 \r \n " , 4 ) ;
ret = redisReaderGetReply ( reader , & reply ) ;
test_cond ( ret = = REDIS_OK & &
( ( redisReply * ) reply ) - > type = = REDIS_REPLY_ARRAY & &
( ( redisReply * ) reply ) - > elements = = 0 ) ;
freeReplyObject ( reply ) ;
redisReaderFree ( reader ) ;
}
static void * test_create_string ( const redisReadTask * task , char * str , size_t len ) {
redisReader * r = ( redisReader * ) task - > privdata ;
const char * roff = r - > buf + r - > roff ;
( ( void ) str ) ; ( ( void ) len ) ;
assert ( task - > plen > 0 ) ;
assert ( task - > clen > 0 ) ;
switch ( task - > type ) {
case REDIS_REPLY_STATUS :
assert ( strncmp ( " +status \r \n " , roff + task - > poff , task - > plen ) = = 0 ) ;
assert ( strncmp ( " status " , roff + task - > coff , task - > clen ) = = 0 ) ;
break ;
case REDIS_REPLY_ERROR :
assert ( strncmp ( " -error \r \n " , roff + task - > poff , task - > plen ) = = 0 ) ;
assert ( strncmp ( " error " , roff + task - > coff , task - > clen ) = = 0 ) ;
break ;
case REDIS_REPLY_STRING : /* bulk */
assert ( strncmp ( " $4 \r \n bulk \r \n " , roff + task - > poff , task - > plen ) = = 0 ) ;
assert ( strncmp ( " bulk " , roff + task - > coff , task - > clen ) = = 0 ) ;
break ;
default :
assert ( NULL ) ;
}
return ( void * ) 1 ;
}
static void * test_create_array ( const redisReadTask * task , int len ) {
redisReader * r = ( redisReader * ) task - > privdata ;
const char * roff = r - > buf + r - > roff ;
( ( void ) len ) ;
assert ( task - > plen > 0 ) ;
assert ( task - > clen = = 0 ) ;
assert ( strncmp ( " *5 \r \n " , roff + task - > poff , task - > plen ) = = 0 ) ;
return ( void * ) 1 ;
}
static void * test_create_integer ( const redisReadTask * task , long long value ) {
redisReader * r = ( redisReader * ) task - > privdata ;
const char * roff = r - > buf + r - > roff ;
( ( void ) value ) ;
assert ( task - > plen > 0 ) ;
assert ( task - > clen > 0 ) ;
assert ( strncmp ( " :1234 \r \n " , roff + task - > poff , task - > plen ) = = 0 ) ;
assert ( strncmp ( " 1234 " , roff + task - > coff , task - > clen ) = = 0 ) ;
return ( void * ) 1 ;
}
static void * test_create_nil ( const redisReadTask * task ) {
redisReader * r = ( redisReader * ) task - > privdata ;
const char * roff = r - > buf + r - > roff ;
assert ( task - > plen > 0 ) ;
assert ( task - > clen = = 0 ) ;
assert ( strncmp ( " $-1 \r \n " , roff + task - > poff , task - > plen ) = = 0 ) ;
return ( void * ) 1 ;
}
static redisReplyObjectFunctions test_reader_fn = {
test_create_string ,
test_create_array ,
test_create_integer ,
test_create_nil ,
NULL
} ;
static void test_reader_functions ( void ) {
redisReader * reader ;
const char * input ;
int ret ;
void * obj ;
input =
" *5 \r \n "
" $-1 \r \n "
" :1234 \r \n "
" +status \r \n "
" -error \r \n "
" $4 \r \n bulk \r \n " ;
test ( " Custom object functions in reply reader: " ) ;
reader = redisReaderCreate ( ) ;
reader - > fn = & test_reader_fn ;
reader - > privdata = reader ;
redisReaderFeed ( reader , input , strlen ( input ) ) ;
ret = redisReaderGetReply ( reader , & obj ) ;
test_cond ( ret = = REDIS_OK & & obj = = ( void * ) 1 ) ;
redisReaderFree ( reader ) ;
}
static void test_blocking_connection_errors ( void ) {
redisContext * c ;
redisReply * reply ;
int major , minor ;
test ( " Returns error when host cannot be resolved: " ) ;
c = redisConnect ( ( char * ) " idontexist.local " , 6379 ) ;
@ -127,30 +363,29 @@ static void test_blocking_connection() {
redisFree ( c ) ;
test ( " Returns error when the port is not open: " ) ;
c = redisConnect ( ( char * ) " localhost " , 56380 ) ;
c = redisConnect ( ( char * ) " localhost " , 1 ) ;
test_cond ( c - > err = = REDIS_ERR_IO & &
strcmp ( c - > errstr , " Connection refused " ) = = 0 ) ;
redisFree ( c ) ;
__connect ( & c ) ;
test ( " Returns error when the unix socket path doesn't accept connections: " ) ;
c = redisConnectUnix ( ( char * ) " /tmp/idontexist.sock " ) ;
test_cond ( c - > err = = REDIS_ERR_IO ) ; /* Don't care about the message... */
redisFree ( c ) ;
}
static void test_blocking_connection ( struct config config ) {
redisContext * c ;
redisReply * reply ;
c = connect ( config ) ;
test ( " Is able to deliver commands: " ) ;
reply = redisCommand ( c , " PING " ) ;
test_cond ( reply - > type = = REDIS_REPLY_STATUS & &
strcasecmp ( reply - > str , " pong " ) = = 0 )
freeReplyObject ( reply ) ;
/* Switch to DB 9 for testing, now that we know we can chat. */
reply = redisCommand ( c , " SELECT 9 " ) ;
freeReplyObject ( reply ) ;
/* Make sure the DB is emtpy */
reply = redisCommand ( c , " DBSIZE " ) ;
if ( reply - > type ! = REDIS_REPLY_INTEGER | | reply - > integer ! = 0 ) {
printf ( " Database #9 is not empty, test can not continue \n " ) ;
exit ( 1 ) ;
}
freeReplyObject ( reply ) ;
test ( " Is a able to send commands verbatim: " ) ;
reply = redisCommand ( c , " SET foo bar " ) ;
test_cond ( reply - > type = = REDIS_REPLY_STATUS & &
@ -214,6 +449,16 @@ static void test_blocking_connection() {
strcasecmp ( reply - > element [ 1 ] - > str , " pong " ) = = 0 ) ;
freeReplyObject ( reply ) ;
disconnect ( c ) ;
}
static void test_blocking_io_errors ( struct config config ) {
redisContext * c ;
redisReply * reply ;
int major , minor ;
/* Connect to target given by config. */
c = connect ( config ) ;
{
/* Find out Redis version to determine the path for the next test */
const char * field = " redis_version: " ;
@ -246,115 +491,80 @@ static void test_blocking_connection() {
* conditions , the error will be set to EOF . */
assert ( c - > err = = REDIS_ERR_EOF & &
strcmp ( c - > errstr , " Server closed the connection " ) = = 0 ) ;
/* Clean up context and reconnect again */
redisFree ( c ) ;
__connect ( & c ) ;
}
static void test_reply_reader ( ) {
void * reader ;
void * reply ;
char * err ;
int ret ;
test ( " Error handling in reply parser: " ) ;
reader = redisReplyReaderCreate ( ) ;
redisReplyReaderFeed ( reader , ( char * ) " @foo \r \n " , 6 ) ;
ret = redisReplyReaderGetReply ( reader , NULL ) ;
err = redisReplyReaderGetError ( reader ) ;
test_cond ( ret = = REDIS_ERR & &
strcasecmp ( err , " Protocol error, got \" @ \" as reply type byte " ) = = 0 ) ;
redisReplyReaderFree ( reader ) ;
/* when the reply already contains multiple items, they must be free'd
* on an error . valgrind will bark when this doesn ' t happen . */
test ( " Memory cleanup in reply parser: " ) ;
reader = redisReplyReaderCreate ( ) ;
redisReplyReaderFeed ( reader , ( char * ) " *2 \r \n " , 4 ) ;
redisReplyReaderFeed ( reader , ( char * ) " $5 \r \n hello \r \n " , 11 ) ;
redisReplyReaderFeed ( reader , ( char * ) " @foo \r \n " , 6 ) ;
ret = redisReplyReaderGetReply ( reader , NULL ) ;
err = redisReplyReaderGetError ( reader ) ;
test_cond ( ret = = REDIS_ERR & &
strcasecmp ( err , " Protocol error, got \" @ \" as reply type byte " ) = = 0 ) ;
redisReplyReaderFree ( reader ) ;
test ( " Set error on nested multi bulks with depth > 1: " ) ;
reader = redisReplyReaderCreate ( ) ;
redisReplyReaderFeed ( reader , ( char * ) " *1 \r \n " , 4 ) ;
redisReplyReaderFeed ( reader , ( char * ) " *1 \r \n " , 4 ) ;
redisReplyReaderFeed ( reader , ( char * ) " *1 \r \n " , 4 ) ;
ret = redisReplyReaderGetReply ( reader , NULL ) ;
err = redisReplyReaderGetError ( reader ) ;
test_cond ( ret = = REDIS_ERR & &
strncasecmp ( err , " No support for " , 14 ) = = 0 ) ;
redisReplyReaderFree ( reader ) ;
test ( " Works with NULL functions for reply: " ) ;
reader = redisReplyReaderCreate ( ) ;
redisReplyReaderSetReplyObjectFunctions ( reader , NULL ) ;
redisReplyReaderFeed ( reader , ( char * ) " +OK \r \n " , 5 ) ;
ret = redisReplyReaderGetReply ( reader , & reply ) ;
test_cond ( ret = = REDIS_OK & & reply = = ( void * ) REDIS_REPLY_STATUS ) ;
redisReplyReaderFree ( reader ) ;
test ( " Works when a single newline ( \\ r \\ n) covers two calls to feed: " ) ;
reader = redisReplyReaderCreate ( ) ;
redisReplyReaderSetReplyObjectFunctions ( reader , NULL ) ;
redisReplyReaderFeed ( reader , ( char * ) " +OK \r " , 4 ) ;
ret = redisReplyReaderGetReply ( reader , & reply ) ;
assert ( ret = = REDIS_OK & & reply = = NULL ) ;
redisReplyReaderFeed ( reader , ( char * ) " \n " , 1 ) ;
ret = redisReplyReaderGetReply ( reader , & reply ) ;
test_cond ( ret = = REDIS_OK & & reply = = ( void * ) REDIS_REPLY_STATUS ) ;
redisReplyReaderFree ( reader ) ;
c = connect ( config ) ;
test ( " Returns I/O error on socket timeout: " ) ;
struct timeval tv = { 0 , 1000 } ;
assert ( redisSetTimeout ( c , tv ) = = REDIS_OK ) ;
test_cond ( redisGetReply ( c , ( void * * ) & reply ) = = REDIS_ERR & &
c - > err = = REDIS_ERR_IO & & errno = = EAGAIN ) ;
redisFree ( c ) ;
}
static void test_throughput ( ) {
int i ;
long long t1 , t2 ;
redisContext * c = blocking_context ;
static void test_throughput ( struct config config ) {
redisContext * c = connect ( config ) ;
redisReply * * replies ;
int i , num ;
long long t1 , t2 ;
test ( " Throughput: \n " ) ;
for ( i = 0 ; i < 500 ; i + + )
freeReplyObject ( redisCommand ( c , " LPUSH mylist foo " ) ) ;
replies = malloc ( sizeof ( redisReply * ) * 1000 ) ;
num = 1000 ;
replies = malloc ( sizeof ( redisReply * ) * num ) ;
t1 = usec ( ) ;
for ( i = 0 ; i < 1000 ; i + + ) {
for ( i = 0 ; i < num ; i + + ) {
replies [ i ] = redisCommand ( c , " PING " ) ;
assert ( replies [ i ] ! = NULL & & replies [ i ] - > type = = REDIS_REPLY_STATUS ) ;
}
t2 = usec ( ) ;
for ( i = 0 ; i < 1000 ; i + + ) freeReplyObject ( replies [ i ] ) ;
for ( i = 0 ; i < num ; i + + ) freeReplyObject ( replies [ i ] ) ;
free ( replies ) ;
printf ( " \t ( 1000x PING: %.2fs)\n " , ( t2 - t1 ) / 1000000.0 ) ;
printf ( " \t (%dx PING: %.3fs) \n " , num , ( t2 - t1 ) / 1000000.0 ) ;
replies = malloc ( sizeof ( redisReply * ) * 1000 ) ;
replies = malloc ( sizeof ( redisReply * ) * num ) ;
t1 = usec ( ) ;
for ( i = 0 ; i < 1000 ; i + + ) {
for ( i = 0 ; i < num ; i + + ) {
replies [ i ] = redisCommand ( c , " LRANGE mylist 0 499 " ) ;
assert ( replies [ i ] ! = NULL & & replies [ i ] - > type = = REDIS_REPLY_ARRAY ) ;
assert ( replies [ i ] ! = NULL & & replies [ i ] - > elements = = 500 ) ;
}
t2 = usec ( ) ;
for ( i = 0 ; i < 1000 ; i + + ) freeReplyObject ( replies [ i ] ) ;
for ( i = 0 ; i < num ; i + + ) freeReplyObject ( replies [ i ] ) ;
free ( replies ) ;
printf ( " \t (1000x LRANGE with 500 elements: %.2fs) \n " , ( t2 - t1 ) / 1000000.0 ) ;
}
printf ( " \t (%dx LRANGE with 500 elements: %.3fs) \n " , num , ( t2 - t1 ) / 1000000.0 ) ;
static void cleanup ( ) {
redisContext * c = blocking_context ;
redisReply * reply ;
num = 10000 ;
replies = malloc ( sizeof ( redisReply * ) * num ) ;
for ( i = 0 ; i < num ; i + + )
redisAppendCommand ( c , " PING " ) ;
t1 = usec ( ) ;
for ( i = 0 ; i < num ; i + + ) {
assert ( redisGetReply ( c , ( void * ) & replies [ i ] ) = = REDIS_OK ) ;
assert ( replies [ i ] ! = NULL & & replies [ i ] - > type = = REDIS_REPLY_STATUS ) ;
}
t2 = usec ( ) ;
for ( i = 0 ; i < num ; i + + ) freeReplyObject ( replies [ i ] ) ;
free ( replies ) ;
printf ( " \t (%dx PING (pipelined): %.3fs) \n " , num , ( t2 - t1 ) / 1000000.0 ) ;
/* Make sure we're on DB 9 */
reply = redisCommand ( c , " SELECT 9 " ) ;
assert ( reply ! = NULL ) ; freeReplyObject ( reply ) ;
reply = redisCommand ( c , " FLUSHDB " ) ;
assert ( reply ! = NULL ) ; freeReplyObject ( reply ) ;
redisFree ( c ) ;
replies = malloc ( sizeof ( redisReply * ) * num ) ;
for ( i = 0 ; i < num ; i + + )
redisAppendCommand ( c , " LRANGE mylist 0 499 " ) ;
t1 = usec ( ) ;
for ( i = 0 ; i < num ; i + + ) {
assert ( redisGetReply ( c , ( void * ) & replies [ i ] ) = = REDIS_OK ) ;
assert ( replies [ i ] ! = NULL & & replies [ i ] - > type = = REDIS_REPLY_ARRAY ) ;
assert ( replies [ i ] ! = NULL & & replies [ i ] - > elements = = 500 ) ;
}
t2 = usec ( ) ;
for ( i = 0 ; i < num ; i + + ) freeReplyObject ( replies [ i ] ) ;
free ( replies ) ;
printf ( " \t (%dx LRANGE with 500 elements (pipelined): %.3fs) \n " , num , ( t2 - t1 ) / 1000000.0 ) ;
disconnect ( c ) ;
}
// static long __test_callback_flags = 0;
@ -376,7 +586,7 @@ static void cleanup() {
// static redisContext *__connect_nonblock() {
// /* Reset callback flags */
// __test_callback_flags = 0;
// return redisConnectNonBlock("127.0.0.1", 6379 , NULL);
// return redisConnectNonBlock("127.0.0.1", port , NULL);
// }
//
// static void test_nonblocking_connection() {
@ -457,23 +667,63 @@ static void cleanup() {
// }
int main ( int argc , char * * argv ) {
if ( argc > 1 ) {
if ( strcmp ( argv [ 1 ] , " -s " ) = = 0 )
use_unix = 1 ;
struct config cfg = {
. tcp = {
. host = " 127.0.0.1 " ,
. port = 6379
} ,
. unix = {
. path = " /tmp/redis.sock "
}
} ;
int throughput = 1 ;
/* Ignore broken pipe signal (for I/O error tests). */
signal ( SIGPIPE , SIG_IGN ) ;
/* Parse command line options. */
argv + + ; argc - - ;
while ( argc ) {
if ( argc > = 2 & & ! strcmp ( argv [ 0 ] , " -h " ) ) {
argv + + ; argc - - ;
cfg . tcp . host = argv [ 0 ] ;
} else if ( argc > = 2 & & ! strcmp ( argv [ 0 ] , " -p " ) ) {
argv + + ; argc - - ;
cfg . tcp . port = atoi ( argv [ 0 ] ) ;
} else if ( argc > = 2 & & ! strcmp ( argv [ 0 ] , " -s " ) ) {
argv + + ; argc - - ;
cfg . unix . path = argv [ 0 ] ;
} else if ( argc > = 1 & & ! strcmp ( argv [ 0 ] , " --skip-throughput " ) ) {
throughput = 0 ;
} else {
fprintf ( stderr , " Invalid argument: %s \n " , argv [ 0 ] ) ;
exit ( 1 ) ;
}
argv + + ; argc - - ;
}
signal ( SIGPIPE , SIG_IGN ) ;
test_format_commands ( ) ;
test_blocking_connection ( ) ;
test_reply_reader ( ) ;
// test_nonblocking_connection();
test_throughput ( ) ;
cleanup ( ) ;
if ( fails = = 0 ) {
printf ( " ALL TESTS PASSED \n " ) ;
} else {
test_reader_functions ( ) ;
test_blocking_connection_errors ( ) ;
printf ( " \n Testing against TCP connection (%s:%d): \n " , cfg . tcp . host , cfg . tcp . port ) ;
cfg . type = CONN_TCP ;
test_blocking_connection ( cfg ) ;
test_blocking_io_errors ( cfg ) ;
if ( throughput ) test_throughput ( cfg ) ;
printf ( " \n Testing against Unix socket connection (%s): \n " , cfg . unix . path ) ;
cfg . type = CONN_UNIX ;
test_blocking_connection ( cfg ) ;
test_blocking_io_errors ( cfg ) ;
if ( throughput ) test_throughput ( cfg ) ;
if ( fails ) {
printf ( " *** %d TESTS FAILED *** \n " , fails ) ;
return 1 ;
}
printf ( " ALL TESTS PASSED \n " ) ;
return 0 ;
}