# API and build change and fix summaries. Doc corrections
# and/or changes are not mentioned here; see the commit messages.
+2021 April 19; version 4.7.3
+ Correct flag check bug in route table functions (RIC-777).
+
2021 April 9; version 4.7.2
Ensure that route table update received from route generator is not
applied before a full route table is received.
set( major_version "4" ) # should be automatically populated from git tag later, but until CI process sets a tag we use this
set( minor_version "7" )
-set( patch_level "2" )
+set( patch_level "3" )
set( install_root "${CMAKE_INSTALL_PREFIX}" )
set( install_inc "include/rmr" )
version 4.0.0, the RMR versions should no longer skip.
+2021 April 19; version 4.7.3
+----------------------------
+
+Correct flag check bug in route table functions (RIC-777).
+
+
+
2021 April 9; version 4.7.2
---------------------------
break;
case 'u': // update current table, not a total replacement
- if( ! ctx->flags & CFL_FULLRT ) { // we cannot update until we have a full table from route generator
+ if( ! (ctx->flags & CFL_FULLRT) ) { // we cannot update until we have a full table from route generator
rmr_vlog( RMR_VL_WARN, "route table update ignored: full table not previously recevied" );
break;
}
static void fd2ep_init( uta_ctx_t* ctx );
static void fd2ep_add( uta_ctx_t* ctx, int fd, endpoint_t* ep );
+// ------ misc ---------------------------------------------------
+static inline void incr_ep_counts( int state, endpoint_t* ep ); // must declare for static includes, but after headers
+
#endif
// vim: ts=4 sw=4 noet :
/*
==================================================================================
- Copyright (c) 2019-2020 Nokia
- Copyright (c) 2018-2020 AT&T Intellectual Property.
+ Copyright (c) 2019-2021 Nokia
+ Copyright (c) 2018-2021 AT&T Intellectual Property.
Licensed under the Apache License, Version 2.0 (the "License");
you may not use this file except in compliance with the License.
#include "si95/socket_if.h"
#include "si95/siproto.h"
+
#define SI95_BUILD 1 // we drop some common functions for si
#include "rmr.h" // things the users see
#include "rmr_agnostic.h" // agnostic things (must be included before private)
#include "rmr_si_private.h" // things that we need too
+
#include "rmr_symtab.h"
#include "rmr_logging.h"
//------------------------------------------------------------------------------
+/*
+ If we have an EP, up the counters based on state.
+ This isn't needed, but it makes driving the code under unit test easier so we
+ induldge in the bean counter's desire for coverage numbers.
+*/
+static inline void incr_ep_counts( int state, endpoint_t* ep ) {
+ if( ep != NULL ) {
+ switch( state ) {
+ case RMR_OK:
+ ep->scounts[EPSC_GOOD]++;
+ break;
+
+ case RMR_ERR_RETRY:
+ ep->scounts[EPSC_TRANS]++;
+ break;
+
+ default:
+ ep->scounts[EPSC_FAIL]++;
+ break;
+ }
+ }
+}
/*
Clean up a context.
}
}
-
msg->state = RMR_OK; // ensure it is clear before send
hold_src = strdup( (char *) ((uta_mhdr_t *)msg->header)->src ); // the dest where we're returning the message to
hold_ip = strdup( (char *) ((uta_mhdr_t *)msg->header)->srcip ); // both the src host and src ip
zt_buf_fill( (char *) ((uta_mhdr_t *)msg->header)->src, ctx->my_name, RMR_MAX_SRC ); // must overlay the source to be ours
msg = send_msg( ctx, msg, nn_sock, -1 );
if( msg ) {
- if( ep != NULL ) {
- switch( msg->state ) {
- case RMR_OK:
- ep->scounts[EPSC_GOOD]++;
- break;
-
- case RMR_ERR_RETRY:
- ep->scounts[EPSC_TRANS]++;
- break;
-
- default:
- // FIX ME uta_fd_failed( nn_sock ); // we don't have an ep so this requires a look up/search to mark it failed
- ep->scounts[EPSC_FAIL]++;
- break;
- }
- }
+ incr_ep_counts( msg->state, ep ); // update counts
+
zt_buf_fill( (char *) ((uta_mhdr_t *)msg->header)->src, hold_src, RMR_MAX_SRC ); // always replace original source & ip so rts can be called again
zt_buf_fill( (char *) ((uta_mhdr_t *)msg->header)->srcip, hold_ip, RMR_MAX_SRC );
msg->flags |= MFL_ADDSRC; // if msg given to send() it must add source
return 0;
}
+/*
+ Common cleanup on initialisation error. These are hard to force, and this helps to ensure
+ all code is tested by providing a callable rather than a block of "goto" code.
+
+ There is a return value so that where we need this we get dinked only for one
+ uncovered line rather than two:
+ init_err(...);
+ return NULL;
+
+ That's a hack, and is yet another example of the testing tail wagging the dog.
+*/
+static inline void* init_err( char* msg, void* ctx, void* port, int errval ) {
+ if( errval != 0 ) { // if not letting it be what a sysllib set it to...
+ errno = errval;
+ }
+
+ if( port ) { // free things if allocated
+ free( port );
+ }
+ if( ctx ) {
+ free_ctx( ctx );
+ }
+
+ if( msg ) { // crit message if supplied
+ rmr_vlog( RMR_VL_CRIT, "rmr_init: %s: %s", msg, strerror( errno ) );
+ }
+
+ return NULL;
+}
/*
This is the actual init workhorse. The user visible function meerly ensures that the
}
if ( proto_port == NULL ){
- errno = ENOMEM;
- return NULL;
+ return init_err( "unable to alloc proto port string", NULL, NULL, ENOMEM );
}
if( (ctx = (uta_ctx_t *) malloc( sizeof( uta_ctx_t ) )) == NULL ) {
- errno = ENOMEM;
- goto err;
+ return init_err( "unable to allocate context", ctx, proto_port, ENOMEM );
}
memset( ctx, 0, sizeof( uta_ctx_t ) );
ctx->si_ctx = SIinitialise( SI_OPT_FG ); // FIX ME: si needs to streamline and drop fork/bg stuff
if( ctx->si_ctx == NULL ) {
- rmr_vlog( RMR_VL_CRIT, "unable to initialise SI95 interface\n" );
- goto err;
+ return init_err( "unable to initialise SI95 interface\n", ctx, proto_port, 0 );
}
if( (port = strchr( proto_port, ':' )) != NULL ) {
free( tok );
} else {
if( (gethostname( wbuf, sizeof( wbuf ) )) != 0 ) {
- rmr_vlog( RMR_VL_CRIT, "rmr_init: cannot determine localhost name: %s\n", strerror( errno ) );
- goto err;
+ return init_err( "cannot determine localhost name\n", ctx, proto_port, 0 );
}
if( (tok = strchr( wbuf, '.' )) != NULL ) {
*tok = 0; // we don't keep domain portion
ctx->my_name = (char *) malloc( sizeof( char ) * RMR_MAX_SRC );
if( snprintf( ctx->my_name, RMR_MAX_SRC, "%s:%s", wbuf, port ) >= RMR_MAX_SRC ) { // our registered name is host:port
- rmr_vlog( RMR_VL_CRIT, "rmr_init: hostname + port must be less than %d characters; %s:%s is not\n", RMR_MAX_SRC, wbuf, port );
- errno = EINVAL;
- goto err;
+ return init_err( "hostname + port is too long", ctx, proto_port, EINVAL );
}
if( (tok = getenv( ENV_NAME_ONLY )) != NULL ) {
snprintf( bind_info, sizeof( bind_info ), "%s:%s", interface, port );
if( (state = SIlistener( ctx->si_ctx, TCP_DEVICE, bind_info )) < 0 ) {
rmr_vlog( RMR_VL_CRIT, "rmr_init: unable to start si listener for %s: %s\n", bind_info, strerror( errno ) );
- goto err;
+ return init_err( NULL, ctx, proto_port, 0 );
}
// finish all flag setting before threads to keep helgrind quiet
ctx->ephash = rmr_sym_alloc( 129 ); // host:port to ep symtab exists outside of any route table
if( ctx->ephash == NULL ) {
- rmr_vlog( RMR_VL_CRIT, "rmr_init: unable to allocate ep hash\n" );
- errno = ENOMEM;
- goto err;
+ return init_err( "unable to allocate ep hash\n", ctx, proto_port, ENOMEM );
}
ctx->rtable = rt_clone_space( ctx, NULL, NULL, 0 ); // create an empty route table so that wormhole/rts calls can be used
free( proto_port );
return (void *) ctx;
-
-err:
- free( proto_port );
- free_ctx( ctx );
- return NULL;
}
/*
msg->header = ((char *) msg->tp_buf) + TP_HDR_LEN;
v1hdr = (uta_v1mhdr_t *) msg->header; // v1 will always allow us to suss out the version
-
- if( v1hdr->rmr_ver == 1 ) { // bug in verion 1 didn't encode the version in network byte order
- ver = 1;
- v1hdr->rmr_ver = htonl( 1 ); // save it correctly in case we clone the message
- } else {
- ver = ntohl( v1hdr->rmr_ver );
- }
+ ver = ntohl( v1hdr->rmr_ver );
switch( ver ) {
- case 1:
- msg->len = ntohl( v1hdr->plen ); // length sender says is in the payload (received length could be larger)
- msg->alloc_len = alen; // length of whole tp buffer (including header, trace and data bits)
- msg->payload = msg->header + sizeof( uta_v1mhdr_t ); // point past header to payload (single buffer allocation above)
+ // version 1 is deprecated case 1:
+ // version 2 is deprecated case 2:
- msg->xaction = &v1hdr->xid[0]; // point at transaction id in header area
- msg->flags |= MFL_ZEROCOPY; // this is a zerocopy sendable message
- msg->mtype = ntohl( v1hdr->mtype ); // capture and convert from network order to local order
- msg->sub_id = UNSET_SUBID; // type 1 messages didn't have this
- msg->state = RMR_OK;
- hlen = sizeof( uta_v1mhdr_t );
- break;
+ case 3:
+ // fall-through
default: // current version always lands here
hdr = (uta_mhdr_t *) msg->header;
nm->header = ((char *) nm->tp_buf) + TP_HDR_LEN;
v1hdr = (uta_v1mhdr_t *) old_msg->header; // v1 will work to dig header out of any version
switch( ntohl( v1hdr->rmr_ver ) ) {
- case 1:
- hdr = nm->header;
- memcpy( hdr, old_msg->header, sizeof( *v1hdr ) ); // copy complete header
- nm->payload = (void *) v1hdr + sizeof( *v1hdr );
- break;
+ // version 1 deprecated case 1:
+ // version 2 deprecated
+ case 3:
+ // fall-through
default: // current message always caught here
hdr = nm->header;
memcpy( hdr, old_msg->header, RMR_HDR_LEN( old_msg->header ) + RMR_TR_LEN( old_msg->header ) + RMR_D1_LEN( old_msg->header ) + RMR_D2_LEN( old_msg->header )); // copy complete header, trace and other data
v1hdr = (uta_v1mhdr_t *) old_msg->header; // v1 will work to dig header out of any version
switch( ntohl( v1hdr->rmr_ver ) ) {
- case 1:
- v1hdr = nm->header;
- memcpy( v1hdr, old_msg->header, sizeof( *v1hdr ) ); // copy complete header
- nm->payload = (void *) v1hdr + sizeof( *v1hdr );
- break;
+ // version 1 not supported
+ // version 2 not supported
+ case 3:
+ // fall-through
default: // current message version always caught here
hdr = nm->header;
return nm;
}
-/*
- For SI95 based transport all receives are driven through the threaded
- ring and thus this function should NOT be called. If it is we will panic
- and abort straight away.
-*/
-static rmr_mbuf_t* rcv_msg( uta_ctx_t* ctx, rmr_mbuf_t* old_msg ) {
-
-fprintf( stderr, "\n\n>>> rcv_msg: bad things just happened!\n\n>>>>>> abort! rcv_msg called and it shouldn't be\n" );
-exit( 1 );
-
- return NULL;
-}
-
/*
This does the hard work of actually sending the message to the given socket. On success,
a new message struct is returned. On error, the original msg is returned with the state
}
}
- if( ep != NULL && msg != NULL ) {
- switch( msg->state ) {
- case RMR_OK:
- ep->scounts[EPSC_GOOD]++;
- break;
-
- case RMR_ERR_RETRY:
- ep->scounts[EPSC_TRANS]++;
- break;
-
- default:
- ep->scounts[EPSC_FAIL]++;
- uta_ep_failed( ep ); // sending to ep failed; set up to reconnect
- break;
- }
+ if( msg != NULL ) {
+ incr_ep_counts( msg->state, ep );
}
} else {
if( DEBUG ) rmr_vlog( RMR_VL_DEBUG, "invalid socket for rte, setting no endpoint err: mtype=%d sub_id=%d\n", msg->mtype, msg->sub_id );
#include "rmr.h"
#include "rmr_agnostic.h"
+/*
+ Driving ep counts is tricky when trying to do it as a part of the rts function, so
+ we drive that code on it's own.
+*/
+static int test_ep_counts() {
+ int errors = 0;
+ struct endpoint ep; // need a dummy endpoint
+
+ memset( &ep, 0, sizeof( ep ) );
+
+ incr_ep_counts( RMR_OK, &ep );
+ errors += fail_if_false( ep.scounts[EPSC_GOOD] == 1, "ep inc good counter had bad value" );
+
+ incr_ep_counts( RMR_ERR_RETRY, &ep );
+ errors += fail_if_false( ep.scounts[EPSC_TRANS] == 1, "ep inc trans counter had bad value" );
+
+ incr_ep_counts( 99, &ep ); // any non-retry/ok value
+ errors += fail_if_false( ep.scounts[EPSC_FAIL] == 1, "ep inc fail counter had bad value" );
+
+ incr_ep_counts( RMR_OK, NULL ); // ensure nil pointer doesn't crash us
+
+ return errors;
+}
+
static int rmr_api_test( ) {
int errors = 0;
void* rmc; // route manager context
setenv( "RMR_RTG_SVC", "-1", 1 ); // force into static table mode
rmr_init( ":6789", 1024, 0 ); // threaded mode with static table
+
+ // ---- some things must be pushed specifically for edge cases and such ------------------------------------
+ errors += test_ep_counts();
+ init_err( "test error message", rmc, rmc2, ENOMEM ); // drive for coverage
+
// --------------- phew, done ------------------------------------------------------------------------------
if( ! errors ) {
SItp_stats( si_ctx ); // drive for coverage only
SItp_stats( NULL );
- SIconnect( si_ctx, "localhost:43086" ); // ensure context has a tp block to free on shutdown
+ SIconnect( si_ctx, "127.0.0.1:43086" ); // ensure context has a tp block to free on shutdown
SIshutdown( NULL );
SIabort( si_ctx );
errors += fail_if_true( l != 0, "SIaddress given two null pointers didn't return 0 len" );
l = SIaddress( buf1, NULL, 0 );
errors += fail_if_true( l != 0, "SIaddress given null dest pointer didn't return 0 len" );
- l = SIaddress( NULL, buf1, 0 );
+ l = SIaddress( NULL, (void *) &buf1, 0 );
errors += fail_if_true( l != 0, "SIaddress given null src pointer didn't return 0 len" );
net_addr = NULL;
snprintf( buf1, sizeof( buf1 ), "[ff02::5]:4002" ); // v6 might not be supported so failure is OK here; driving for coverage
l = SIaddress( buf1, &net_addr, AC_TOADDR6 );
if( l > 0 ) {
- l = SIaddress( net_addr, &hr_addr, AC_TODOT ); // convert the address back to hr string
+ l = SIaddress( net_addr, (void *) &hr_addr, AC_TODOT ); // convert the address back to hr string
errors += fail_if_true( l < 1, "v6 to dot conversion failed" );
errors += fail_if_nil( hr_addr, "v6 to dot conversion yields a nil pointer" );
free( net_addr );
l = SIaddress( buf1, (void **) &net_addr, AC_TOADDR );
errors += fail_if_true( l < 1, "v4 to addr conversion failed" );
- l = SIaddress( net_addr, &hr_addr, AC_TODOT ); // convert the address back to hr string
+ l = SIaddress( net_addr, (void *) &hr_addr, AC_TODOT ); // convert the address back to hr string
errors += fail_if_true( l < 1, "to dot convdersion failed" );
errors += fail_if_nil( hr_addr, "v4 to dot conversion yields a nil pointer" );
free( net_addr );
errors += fail_not_equal( strncmp( payload_str, mbuf->payload, strlen( payload_str )), 0, "realloc payload (clone+nocopy) validation of unchanged payload fails" );
+ // ---------------------- misc coverage tests; nothing to verify other than they don't crash -----------------------
+ payload_str = strdup( "The Marching 110 will play the OU fightsong after every touchdown or field goal; it is a common sound echoing from Peden Stadium in the fall." );
+
+ dump_n( payload_str, "A dump", strlen( payload_str ) );
+ dump_40( payload_str, "another dump" );
+
return !!errors;
+
}
int fd;
char* rt_stuff; // strings for the route table
-ctx->flags |= 0x08;
fd = open( "utesting.rt", O_WRONLY | O_CREAT, 0600 );
if( fd < 0 ) {
fprintf( stderr, "<BUGGERED> unable to open file for testing route table gen\n" );
}
rt_stuff =
+ "updatert|start\n" // update check before whole table received
+ "updatert|end\n"
"newrt|end\n" // end of table check before start of table found
"# comment to drive full comment test\n"
"\n" // handle blank lines
static int fail_if_equal( int a, int b, char* what ) {
ts_tests_driven++;
- fprintf( stderr, "<TESTING> %s %d\n", what, a==b );
if( a == b ) {
fprintf( stderr, "<FAIL> %s values were equal a=%d b=%d\n", what, a, b );
}
+ if_addrs_t* ifl; // interface lis2
// : vi ts=4 sw=4 noet :
/*
==================================================================================
- Copyright (c) 2019 Nokia
- Copyright (c) 2018-2019 AT&T Intellectual Property.
+ Copyright (c) 2019-2021 Nokia
+ Copyright (c) 2018-2021 AT&T Intellectual Property.
Licensed under the Apache License, Version 2.0 (the "License");
you may not use this file except in compliance with the License.
Date: 3 April 2019
*/
-// ------------ zero termianted buffer ---------------------------------------------------------
-static int ztbf_test() {
- int errors = 0;
- char buf[128];
- char* sshort = "Stand up and cheer! Cheer long and loud for old Ohio.";
- char* slong = "Now is the time for the bobcat in the forest to make its way back to Court St for a round of pints at the Pub.";
- int l1;
-
- l1 = zt_buf_fill( buf, sshort, 64 );
- errors += fail_not_equal( l1, strlen( sshort ), "zt_buf_fill of short buf returned unexpected len" );
- errors += fail_not_equal( l1, strlen( buf ), "zt_buf_fill of short buf returned len did not match strlen" );
-
- l1 = zt_buf_fill( buf, slong, 64 );
- errors += fail_if_equal( l1, strlen( slong ), "zt_buf_fill of long buf returned unexpected len" );
- errors += fail_not_equal( l1, strlen( buf ), "zt_buf_fill of long buf returned len did not match strlen" );
+#define MAX_TOKENS 127
- l1 = zt_buf_fill( buf, sshort, strlen( sshort ) ); // edge case of exact size
- errors += fail_not_equal( l1, strlen( sshort )-1, "zt_buf_fill exact length edge case failed" );
+// -------------------- testing support internal functions ------------------------------
+/*
+ Returns an interface name that is valid in this environment (keeps us from
+ having to know/guess a name to test with.
+*/
+static char* get_ifname( ) {
+ struct ifaddrs *ifs; // pointer to head
+ struct ifaddrs *ele; // pointer into the list
+ char* rstr = NULL; // return string
+ char octs[NI_MAXHOST+1];
- l1 = zt_buf_fill( buf, sshort, 1 ); // unrealistic edge case
- errors += fail_not_equal( l1, 0, "zt_buf_fill dest len == 1 test failed" );
+ getifaddrs( &ifs );
+ for( ele = ifs; ele; ele = ele->ifa_next ) {
+ if( ele && strcmp( ele->ifa_name, "lo" ) ) {
+ memset( octs, 0, sizeof( octs ) );
+ getnameinfo( ele->ifa_addr, sizeof( struct sockaddr_in6 ), octs, NI_MAXHOST, NULL, 0, NI_NUMERICHOST );
+ if( *octs ) {
+ rstr = strdup( ele->ifa_name );
+ fprintf( stderr, "<INFO> found interface with address: %s\n", rstr );
+ break;
+ }
+ }
+ }
- return errors;
+ if( rstr == NULL ) {
+ fprintf( stderr, "<ERROR> no interface with an address was found!\n" );
+ }
+ return rstr;
}
/*
- Returns an interface name that is valid in this environment (keeps us from
- having to know/guess a name to test with.
+ Build an if-addr list from what we "see" on the current system. Keeps us from
+ having to guess about what we _might_ find in some random test setup.
+ If the inc_lo0 boolean is true, then the loop back address(es) will be
+ included.
*/
-static char* get_ifname( ) {
+static if_addrs_t* get_iflist( int inc_lo0 ) {
if_addrs_t* l;
struct ifaddrs *ifs; // pointer to head
struct ifaddrs *ele; // pointer into the list
- char* rstr = NULL; // return string
char octs[NI_MAXHOST+1];
+ int max_addrs = 128;
if( (l = (if_addrs_t *) malloc( sizeof( if_addrs_t ) )) == NULL ) {
+ fprintf( stderr, "<FAIL> malloc of if_addrs failed\n" );
return NULL;
}
memset( l, 0, sizeof( if_addrs_t ) );
- l->addrs = (char **) malloc( sizeof( char* ) * 128 );
+ l->addrs = (char **) malloc( sizeof( char* ) * max_addrs );
if( l->addrs == NULL ) {
+ fprintf( stderr, "<FAIL> malloc of if_addrs array failed\n" );
free( l );
return NULL;
}
getifaddrs( &ifs );
for( ele = ifs; ele; ele = ele->ifa_next ) {
- if( ele && strcmp( ele->ifa_name, "lo" ) ) {
+ if( ele && (inc_lo0 || strcmp( ele->ifa_name, "lo" )) ) {
memset( octs, 0, sizeof( octs ) );
getnameinfo( ele->ifa_addr, sizeof( struct sockaddr_in6 ), octs, NI_MAXHOST, NULL, 0, NI_NUMERICHOST );
- if( *octs ) {
- rstr = strdup( ele->ifa_name );
- fprintf( stderr, "<INFO> found interface with address: %s\n", rstr );
- break;
+ if( *octs && l->naddrs < max_addrs ) {
+ l->addrs[l->naddrs] = strdup( ele->ifa_name );
+ l->naddrs++;
}
}
}
- free( l );
- if( rstr == NULL ) {
- fprintf( stderr, "<ERROR> no interface with an address was found!\n" );
- }
- return rstr;
+ return l;
}
-static int tools_test( ) {
+
+
+// ------------ internal functions to drive various categories of tests --------------------------------------
+
+static int ztbf_test() {
+ int errors = 0;
+ char buf[128];
+ char* sshort = "Stand up and cheer! Cheer long and loud for old Ohio.";
+ char* slong = "Now is the time for the bobcat in the forest to make its way back to Court St for a round of pints at the Pub.";
+ int l1;
+
+ l1 = zt_buf_fill( NULL, sshort, 64 ); // drive for coverage
+ errors += fail_not_equal( l1, -1, "nil check (buf) on zt_buf_fill did not return expected value" );
+ l1 = zt_buf_fill( buf, NULL, 64 );
+ errors += fail_not_equal( l1, -1, "nil check (str) on zt_buf_fill did not return expected value" );
+
+ l1 = zt_buf_fill( buf, sshort, 64 );
+ errors += fail_not_equal( l1, strlen( sshort ), "zt_buf_fill of short buf returned unexpected len" );
+ errors += fail_not_equal( l1, strlen( buf ), "zt_buf_fill of short buf returned len did not match strlen" );
+
+ l1 = zt_buf_fill( buf, slong, 64 );
+ errors += fail_if_equal( l1, strlen( slong ), "zt_buf_fill of long buf returned unexpected len" );
+ errors += fail_not_equal( l1, strlen( buf ), "zt_buf_fill of long buf returned len did not match strlen" );
+
+ l1 = zt_buf_fill( buf, sshort, strlen( sshort ) ); // edge case of exact size
+ errors += fail_not_equal( l1, strlen( sshort )-1, "zt_buf_fill exact length edge case failed" );
+
+ l1 = zt_buf_fill( buf, sshort, 1 ); // unrealistic edge case
+ errors += fail_not_equal( l1, 0, "zt_buf_fill dest len == 1 test failed" );
+
+ return errors;
+}
+
+/*
+ various tokenising tests.
+*/
+static int tok_tests( ) {
int i;
int j;
- int errors = 0;
- char* tokens[127];
- char* buf = "2,Fred,Wilma,Barney,Betty,Dino,Pebbles,Bambam,Mr. Slate,Gazoo";
char* dbuf; // duplicated buf since C marks a const string is unumtable
- char* hname;
- char* ip; // ip address string
- uta_ctx_t ctx; // context for uta_lookup test
- void* if_list;
-
+ char* buf = "2,Fred,Wilma,Barney,Betty,Dino,Pebbles,Bambam,Mr. Slate,Gazoo";
+ char* tokens[MAX_TOKENS];
+ int errors = 0;
+ if_addrs_t* ifl; // interface list
+ int ntokens;
- uta_dump_env();
+ i = uta_tokenise( NULL, tokens, MAX_TOKENS, ',' ); // nil check coverage
+ errors += fail_not_equal( i, 0, "uta_tokenise did not fail when given nil pointer" );
- // ------------------ tokenise tests -----------------------------------------------------------
dbuf = strdup( buf );
- i = uta_tokenise( dbuf, tokens, 127, ',' );
+ i = uta_tokenise( dbuf, tokens, MAX_TOKENS, ',' );
errors += fail_not_equal( i, 10, "unexpected number of tokens returned (comma sep)" );
for( j = 0; j < i; j++ ) {
//fprintf( stderr, ">>>> [%d] (%s)\n", j, tokens[j] );
free( dbuf );
dbuf = strdup( buf );
- i = uta_tokenise( dbuf, tokens, 127, '|' );
+ i = uta_tokenise( dbuf, tokens, MAX_TOKENS, '|' );
errors += fail_not_equal( i, 1, "unexpected number of tokens returned (bar sep)" );
free( dbuf );
- // ------------ has str tests -----------------------------------------------------------------
- j = uta_has_str( buf, "Mr. Slate", ',', 1 ); // should fail (-1) because user should use strcmp in this situation
- errors += fail_if_true( j >= 0, "test to ensure has str rejects small max" );
-
- j = uta_has_str( buf, "Mr. Slate", ',', 27 );
- errors += fail_if_true( j < 0, "has string did not find Mr. Slate" );
-
- j = uta_has_str( buf, "Mrs. Slate", ',', 27 );
- errors += fail_if_true( j >= 0, "has string not found Mrs. Slate" );
-
- // ------------ host name 2 ip tests ---------------------------------------------------------
- hname = uta_h2ip( "192.168.1.2" );
- errors += fail_not_equal( strcmp( hname, "192.168.1.2" ), 0, "h2ip did not return IP address when given address" );
- errors += fail_if_nil( hname, "h2ip did not return a pointer" );
- free( hname );
-
- hname = uta_h2ip( "yahoo.com" );
- errors += fail_if_nil( hname, "h2ip did not return a pointer" );
- free( hname );
-
- hname = uta_h2ip( "yahoo.com:1234" ); // should ignore the port
- errors += fail_if_nil( hname, "h2ip did not return a pointer" );
- free( hname );
-
- // ------------ rtg lookup test -------------------------------------------------------------
-#ifdef KEEP
- // pub/sub route table generator is deprecated and should be removed at this point
- ctx.rtg_port = 0;
- ctx.rtg_addr = NULL;
-
- i = uta_lookup_rtg( NULL ); // ensure it handles a nil context
- errors += fail_if_true( i, "rtg lookup returned that it found something when not expected to (nil context)" );
-
- setenv( "RMR_RTG_SVC", "localhost:1234", 1);
- i = uta_lookup_rtg( &ctx );
- errors += fail_if_false( i, "rtg lookup returned that it did not find something when expected to" );
- errors += fail_if_nil( ctx.rtg_addr, "rtg lookup did not return a pointer (with port)" );
- errors += fail_not_equal( ctx.rtg_port, 1234, "rtg lookup did not capture the port" );
+ if( (ifl = get_iflist( 1 )) == NULL ) {
+ errors++;
+ fprintf( stderr, "<FAIL> unable to generate an interface list for tokenising tests\n" );
+ return errors;
+ }
- setenv( "RMR_RTG_SVC", "localhost", 1); // test ability to generate default port
- uta_lookup_rtg( &ctx );
- errors += fail_if_nil( ctx.rtg_addr, "rtg lookup did not return a pointer (no port)" );
- errors += fail_not_equal( ctx.rtg_port, 5656, "rtg lookup did not return default port" );
+ dbuf = strdup( "lo0,en0,en1,wlan0,wlan1" ); // must have a mutable string for call
+ ntokens = uta_rmip_tokenise( dbuf, ifl, tokens, MAX_TOKENS, ',' ); // should find at least lo0
+ errors += fail_if_true( ntokens < 1, "rmip tokenise didn't find an interface in the list" );
- unsetenv( "RMR_RTG_SVC" ); // this should fail as the default name (rtg) will be unknown during testing
- i = uta_lookup_rtg( &ctx );
- errors += fail_if_true( i, "rtg lookup returned that it found something when not expected to" );
-#endif
+ return errors;
+}
- // ------------ my_ip stuff -----------------------------------------------------------------
+/*
+ Tests related to finding and validating my ip address.
+*/
+static int my_ip() {
+ int i;
+ int errors = 0;
+ char* ip; // ip address string
+ void* if_list;
if_list = mk_ip_list( "1235" );
errors += fail_if_nil( if_list, "mk_ip_list returned nil pointer" );
fprintf( stderr, "<SKIP> test skipped because no interface with address could be found on system" );
}
- errors += ztbf_test(); // test the zero term buffer fill function
+ return errors;
+}
+
+/*
+ String tools related tests.
+*/
+static int str_tests() {
+ int j;
+ char* buf = "2,Fred,Wilma,Barney,Betty,Dino,Pebbles,Bambam,Mr. Slate,Gazoo";
+ int errors = 0;
+
+ j = uta_has_str( buf, "Mr. Slate", ',', 1 ); // should fail (-1) because user should use strcmp in this situation
+ errors += fail_if_true( j >= 0, "test to ensure has str rejects small max" );
+
+ j = uta_has_str( buf, "Mr. Slate", ',', 27 );
+ errors += fail_if_true( j < 0, "has string did not find Mr. Slate" );
+
+ j = uta_has_str( buf, "Mrs. Slate", ',', 27 );
+ errors += fail_if_true( j >= 0, "has string not found Mrs. Slate" );
+
+ return errors;
+}
+
+/*
+ Tests related to host name tools.
+*/
+static int hostname_tests() {
+ int errors = 0;
+ char* hname;
+
+
+ hname = uta_h2ip( "192.168.1.2" );
+ errors += fail_not_equal( strcmp( hname, "192.168.1.2" ), 0, "h2ip did not return IP address when given address" );
+ errors += fail_if_nil( hname, "h2ip did not return a pointer" );
+ free( hname );
+
+ hname = uta_h2ip( "yahoo.com" );
+ errors += fail_if_nil( hname, "h2ip did not return a pointer" );
+ free( hname );
+
+ hname = uta_h2ip( "yahoo.com:1234" ); // should ignore the port
+ errors += fail_if_nil( hname, "h2ip did not return a pointer" );
+ free( hname );
+
+ hname = uta_h2ip( "bugaboofoo.com:1234" ); // should not be there
+ errors += fail_not_nil( hname, "h2ip lookup returned non-nil when given bogus name" );
+
+ return errors;
+}
+
+/*
+ Misc coverage mostly.
+*/
+static int misc_tests() {
+ int errors = 0;
+ int v;
+ if_addrs_t* ifl; // interface list
+
+ if( (ifl = get_iflist( 1 )) != NULL ) {
+ v = is_this_myip( ifl, NULL );
+ errors += fail_if_false( v == 0, "is this my ip didn't fail when given nil address" );
+ }
+
+ return errors;
+}
+// ----------------------------------------------------------------------------------------------------------------------
+
+
+/*
+ Primary test function driven by the testing main().
+*/
+static int tools_test( ) {
+ int errors = 0;
+
+ uta_dump_env();
-// -------------------------------------------------------------------------------------------------
+ errors += tok_tests();
+ errors += my_ip();
+ errors += str_tests();
+ errors += hostname_tests();
+ errors += ztbf_test();
+ test_summary( errors, "tools" );
return !!errors; // 1 or 0 regardless of count
}
#include "tools_static.c"
#include "tools_static_test.c"
+#include "wrapper_static_test.c"
int main( ) {
int errors = 0;
- fprintf( stderr, ">>>> starting tools_test\n" );
+ fprintf( stderr, "<INFO> starting tools_test\n" );
errors += tools_test() > 0;
+ fprintf( stderr, "<INFO> testing wrapper\n" );
+ errors += wrapper_test();
+
test_summary( errors, "tool tests" );
if( errors == 0 ) {
fprintf( stderr, "<PASS> all tool tests were OK\n\n" );
flist="$@"
fi
-
if (( noexec ))
then
echo "no exec mode; would test these:"
--- /dev/null
+// : vi ts=4 sw=4 noet :
+/*
+==================================================================================
+ Copyright (c) 2021 Nokia
+ Copyright (c) 2021 AT&T Intellectual Property.
+
+ Licensed under the Apache License, Version 2.0 (the "License");
+ you may not use this file except in compliance with the License.
+ You may obtain a copy of the License at
+
+ http://www.apache.org/licenses/LICENSE-2.0
+
+ Unless required by applicable law or agreed to in writing, software
+ distributed under the License is distributed on an "AS IS" BASIS,
+ WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ See the License for the specific language governing permissions and
+ limitations under the License.
+==================================================================================
+*/
+
+
+/*
+ Mnemonic: wrapper_static_test.c
+ Abstract: Unit test for the wrapper module in common.
+
+ Author: E. Scott Daniels
+ Date: 19 April 2020
+*/
+
+#include <wrapper.c>
+
+/*
+ Called by the test driver (main). Returns the number of errors found.
+*/
+static int wrapper_test( ) {
+ int errors = 0;
+ char* b;
+ int len;
+
+ b = rmr_get_consts(); // function that builds constant json string for python-like things
+
+ if( fail_if_equal( strlen( b ), 0, "wrapper buffer had nothing" ) ) {
+ return 1; // can't do any further checking
+ }
+
+ errors += fail_if_true( *b != '{', "first character in buffer not valid json" );
+ len = strlen( b ) - 1;
+ errors += fail_if_true( *(b+len) != '}', "last character in buffer not valid json" );
+ free( b );
+
+ b = build_sval( "foobar", "value", 1 );
+ errors += fail_if_equal( strlen( b ), 0, "build svalue with sep returned nil buffer" );
+ errors += fail_not_equal( strcmp( b, "\"foobar\": \"value\"," ), 0, "svalue result not the expected string" );
+
+ b = build_sval( "foobar", "value", 0 );
+ errors += fail_if_equal( strlen( b ), 0, "build svalue without sep returned nil buffer" );
+ errors += fail_not_equal( strcmp( b, "\"foobar\": \"value\"" ), 0, "svalue result without sep not the expected string" );
+
+
+ // -------------------------------------------------------------------------------------------------
+
+ return !!errors; // 1 or 0 regardless of count
+}