#include <errno.h>
#include <string.h>
#include <stdint.h>
+#include <pthread.h>
+#include <semaphore.h>
-#include "../src/common/include/rmr.h"
-#include "../src/common/include/rmr_agnostic.h"
+#include "rmr.h"
+#include "rmr_agnostic.h"
/*
Send a 'burst' of messages to drive some send retry failures to increase RMr coverage
}
}
+/*
+ Refresh or allocate a message with some default values
+*/
+static rmr_mbuf_t* fresh_msg( void* ctx, rmr_mbuf_t* msg ) {
+ if( ! msg ) {
+ msg = rmr_alloc_msg( ctx, 2048 );
+ }
+
+ msg->mtype = 0;
+ msg->sub_id = -1;
+ msg->state = 0;
+ msg->len = 100;
+
+ return msg;
+}
+
static int rmr_api_test( ) {
int errors = 0;
void* rmc; // route manager context
v = rmr_ready( NULL );
errors += fail_if( v != 0, "rmr_ready returned true before initialisation " );
+ em_set_long_hostname( 1 );
if( (rmc = rmr_init( "4560", 1024, FL_NOTHREAD )) == NULL ) {
fail_if_nil( rmc, "rmr_init returned a nil pointer " );
return 1;
}
+ setenv( "RMR_SRC_ID", "somehost", 1 ); // context should have this as source
if( (rmc2 = rmr_init( ":6789", 1024, FL_NOTHREAD )) == NULL ) { // init without starting a thread
errors += fail_if_nil( rmc, "rmr_init returned a nil pointer for non-threaded init " );
}
+ fprintf( stderr, "<INFO> with RMR_SRC_ID env set, source name in context: (%s)\n", ((uta_ctx_t *) rmc2)->my_name );
+ v = strcmp( ((uta_ctx_t *) rmc2)->my_name, "somehost:6789" );
+ errors += fail_not_equal( v, 0, "source name not set from environment variable (see previous info)" );
free_ctx( rmc2 ); // coverage
-
+
+ unsetenv( "RMR_SRC_ID" ); // context should NOT have our artificial name
if( (rmc2 = rmr_init( NULL, 1024, FL_NOTHREAD )) == NULL ) { // drive default port selector code
errors += fail_if_nil( rmc, "rmr_init returned a nil pointer when driving for default port " );
}
+ fprintf( stderr, "<INFO> after unset of RMR_SRC_ID, source name in context: (%s)\n", ((uta_ctx_t *) rmc2)->my_name );
+ v = strcmp( ((uta_ctx_t *) rmc2)->my_name, "somehost:6789" );
+ errors += fail_if_equal( v, 0, "source name smells when removed from environment (see previous info)" );
+ free_ctx( rmc2 ); // attempt to reduce leak check errors
+
v = rmr_ready( rmc ); // unknown return; not checking at the moment
msg = rmr_alloc_msg( NULL, 1024 ); // should return nil pointer
errors += fail_not_nil( msg, "rmr_alloc_msg didn't return nil when given nil context " );
+
msg = rmr_alloc_msg( rmc, 2048 ); // allocate larger than default size given on init
errors += fail_if_nil( msg, "rmr_alloc_msg returned nil msg pointer " );
+ if( msg ) {
+ rmr_get_srcip( msg, wbuf );
+ errors += fail_if_equal( 0, strlen( wbuf ), "rmr_get_srcip did not did not return string with length (b) after alloc_msg" );
+ fprintf( stderr, "<INFO> ip: %s\n", wbuf );
+ }
+
v = rmr_payload_size( NULL );
errors += fail_if( v >= 0, "rmr_payload_size returned valid size for nil message " );
msg->len = 100;
msg->mtype = 1;
msg->state = 999;
+ msg->tp_state = 999;
errno = 999;
msg = rmr_send_msg( rmc, msg );
errors += fail_if_nil( msg, "send_msg_ did not return a message on send " );
if( msg ) {
errors += fail_not_equal( msg->state, RMR_ERR_NOENDPT, "send_msg did not return no endpoints before rtable added " );
errors += fail_if( errno == 0, "send_msg did not set errno " );
+ errors += fail_if( msg->tp_state == 999, "send_msg did not set tp_state (1)" );
}
gen_rt( rmc ); // --- after this point there is a dummy route table so send and rts calls should be ok
msg->len = 100;
msg->mtype = 1;
msg->state = 999;
+ msg->tp_state = 999;
errno = 999;
msg = rmr_send_msg( rmc, msg );
errors += fail_if_nil( msg, "send_msg_ did not return a message on send " );
errors += fail_if( errno != 0, "send_msg set errno for send that should work " );
v = rmr_payload_size( msg );
errors += fail_if( v != 2048, "send_msg did not allocate new buffer with correct size " );
+ errors += fail_if( msg->tp_state == 999, "send_msg did not set tp_state (2)" );
}
rmr_set_stimeout( NULL, 0 );
if( msg2->state != RMR_ERR_EMPTY ) {
errors += fail_not_equal( msg2->state, RMR_OK, "receive given nil message did not return msg with good state (not empty) " );
}
- //errors += fail_not_equal( msg2->state, RMR_OK, "receive given nil message did not return msg with good state " );
}
msg->state = 0;
msg = rmr_rts_msg( NULL, msg ); // should set state in msg
- errors += fail_if_equal( msg->state, 0, "rmr_rts_msg did not set state when given valid message but no context " );
+ if( msg ) {
+ errors += fail_if_equal( msg->state, 0, "rmr_rts_msg did not set state when given valid message but no context " );
+ } else {
+ errors += fail_if_nil( msg, "rmr_rts_msg returned a nil msg when given a good one" );
+ }
msg = rmr_rts_msg( rmc, msg ); // return the buffer to the sender
errors += fail_if_nil( msg, "rmr_rts_msg did not return a message pointer " );
- errors += fail_if( errno != 0, "rmr_rts_msg did not reset errno " );
+ errors += fail_not_equal( msg->state, 0, "rts_msg did not return a good state (a) when expected" );
+ errors += fail_not_equal( errno, 0, "rmr_rts_msg did not reset errno (a) expected (b)" );
- snprintf( msg->xaction, 17, "%015d", 16 ); // dummy transaction id (emulation generates, this should arrive after a few calls to recv)
msg->state = 0;
msg = rmr_call( NULL, msg );
errors += fail_if( msg->state == 0, "rmr_call did not set message state when given message with nil context " );
+ snprintf( msg->xaction, 17, "%015d", 16 ); // dummy transaction id (emulation generates, this should arrive after a few calls to recv)
msg->mtype = 0;
- msg = rmr_call( rmc, msg ); // this call should return a message as we can anticipate a dummy message in
+ msg->sub_id = -1;
+ em_set_rcvcount( 0 ); // reset message counter
+ em_set_rcvdelay( 1 ); // force slow msg rate during mt testing
+ msg = rmr_call( rmc, msg ); // dummy nng/nano function will sequentually add xactions and should match or '16'
errors += fail_if_nil( msg, "rmr_call returned a nil message on call expected to succeed " );
if( msg ) {
errors += fail_not_equal( msg->state, RMR_OK, "rmr_call did not properly set state on successful return " );
errors += fail_not_equal( errno, 0, "rmr_call did not properly set errno (a) on successful return " );
}
- snprintf( wbuf, 17, "%015d", 14 ); // if we call receive we should find this in the first 15 tries
- for( i = 0; i < 16; i++ ) {
+ snprintf( wbuf, 17, "%015d", 14 ); // while waiting, the queued messages should have #14, so issue a few receives looking for it
+ for( i = 0; i < 16; i++ ) { // it should be in the first 15
msg = rmr_rcv_msg( rmc, msg );
if( msg ) {
if( strcmp( wbuf, msg->xaction ) == 0 ) { // found the queued message
if( ! msg ) {
msg = rmr_alloc_msg( rmc, 2048 ); // something buggered above; get a new one
}
- msg = rmr_call( rmc, msg ); // make a call that we never expect a response on
- errors += fail_if_nil( msg, "rmr_call returned a non-nil message on call expected not to receive a response " );
- if( msg ) {
- errors += fail_if_equal( msg->state, RMR_OK, "rmr_call did not properly set state on queued message receive " );
- errors += fail_if( errno == 0, "rmr_call did not properly set errno on queued message receivesuccessful " );
- }
-
- msg = rmr_call( rmc, msg ); // this should "timeout" because the message xaction id won't ever appear again
- errors += fail_if_nil( msg, "rmr_call returned a nil message on call expected to fail " );
+ msg->mtype = 0;
+ msg->sub_id = -1;
+ msg = rmr_call( rmc, msg ); // make a call that we never expect a response on (nil pointer back)
+ errors += fail_not_nil( msg, "rmr_call returned a nil message on call expected not to receive a response " );
errors += fail_if( errno == 0, "rmr_call did not set errno on failure " );
rmr_free_msg( NULL ); // drive for coverage; nothing to check
errors += fail_if( i >= 40, "torcv_msg never returned a timeout " );
- // ---- trace things that are not a part of the mbuf_api functions and thus must be tested here
+ // ---- trace things that are not a part of the mbuf_api functions and thus must be tested here -------
state = rmr_init_trace( NULL, 37 ); // coverage test nil context
errors += fail_not_equal( state, 0, "attempt to initialise trace with nil context returned non-zero state (a) " );
errors += fail_if_equal( errno, 0, "attempt to initialise trace with nil context did not set errno as expected " );
em_send_failures = 0;
+ ((uta_ctx_t *)rmc)->shutdown = 1;
rmr_close( NULL ); // drive for coverage
rmr_close( rmc ); // no return to check; drive for coverage
+ // -- allocate a new context for mt-call and drive that stuff -----------------------------------------
+#ifdef EMULATE_NNG
+ msg = fresh_msg( rmc, msg ); // ensure we have one with known contents
+
+ msg->state = 0;
+ msg = rmr_mt_call( rmc, msg, 3, 10 ); // drive when not in mt setup
+ if( msg ) {
+ errors += fail_not_equal( msg->state, RMR_ERR_NOTSUPP, "rmr_mt_call did not set not supported error when not mt initialised" );
+ } else {
+ errors += fail_if_nil( msg, "rmr_mt_call returned nil pointer when not mt initialised" );
+ }
+ msg = fresh_msg( rmc, msg );
+
+ msg = rmr_mt_rcv( rmc, msg, 10 ); // gen not supported error if ctx not set for mt
+ if( msg ) {
+ errors += fail_not_equal( msg->state, RMR_ERR_NOTSUPP, "rmr_mt_rcv did not return not supported state when mt not initialised" );
+ } else {
+ errors += fail_if_nil( msg, "nil pointer from rmr_mt_rcv when mt not initialised\n" );
+ }
+ msg = fresh_msg( rmc, msg );
+
+ msg->state = 0;
+ if( msg ) {
+ msg = rmr_mt_call( rmc, msg, 1000, 10 ); // thread id out of range
+ errors += fail_if_equal( msg->state, 0, "rmr_mt_call did not set an error when given an invalid call-id" );
+ } else {
+ errors += fail_if_nil( msg, "rmr_mt_call returned a nil pointer when given an invalid call-id" );
+ }
+ msg = fresh_msg( rmc, msg );
+
+ state = init_mtcall( NULL ); // drive for coverage
+ errors += fail_not_equal( state, 0, "init_mtcall did not return false (a) when given a nil context pointer" );
+
+
+ if( (rmc = rmr_init( NULL, 1024, FL_NOTHREAD | RMRFL_MTCALL )) == NULL ) { // drive multi-call setup code without rtc thread
+ errors += fail_if_nil( rmc, "rmr_init returned a nil pointer when driving for mt-call setup " );
+ }
+
+ gen_rt( rmc ); // must attach a route table so sends succeed
+
+ fprintf( stderr, "<INFO> enabling mt messages\n" );
+ em_set_rcvdelay( 1 ); // force slow msg rate during mt testing
+ em_set_mtc_msgs( 1 ); // emulated nngrcv will now generate messages with call-id and call flag
+
+ msg->state = 0;
+ msg = rmr_mt_call( NULL, msg, 3, 10 ); // should timeout
+ if( msg ) {
+ errors += fail_if( msg->state == 0, "rmr_mt_call did not set message state when given message with nil context " );
+ }
+ msg = fresh_msg( rmc, msg );
+
+ fprintf( stderr, "<INFO> invoking mt_call with timout == 2999\n" );
+ msg = rmr_mt_call( rmc, msg, 2, 2999 ); // long timeout to drive time building code, should receive
+ if( msg ) {
+ if( msg->state != RMR_OK ) {
+ fprintf( stderr, "<INFO> rmr_mt_call returned error in mbuf: %d\n", msg->state );
+ } else {
+ errors += fail_not_nil( msg, "rmr_mt_call did not return a nil pointer on read timeout" );
+ }
+ }
+ msg = fresh_msg( rmc, msg );
+
+ msg = rmr_mt_rcv( NULL, NULL, 10 );
+ errors += fail_not_nil( msg, "rmr_mt_rcv returned a non-nil message when given nil message and nil context" );
+
+ fprintf( stderr, "<INFO> invoking mt_rcv with timout == 2999\n" );
+ msg = fresh_msg( rmc, msg );
+ msg = rmr_mt_rcv( rmc, msg, 2999 );
+ if( !msg ) {
+ errors += fail_if_nil( msg, "rmr_mt_rcv returned a nil message when given valid message and timeout of 29999" );
+ }
+ msg = fresh_msg( rmc, msg );
+
+ msg = rmr_mt_rcv( rmc, msg, -1 );
+ if( !msg ) {
+ errors += fail_if_nil( msg, "rmr_mt_rcv returned a nil message when given valid message unlimited timeout" );
+ }
+ msg = fresh_msg( rmc, msg );
+
+ fprintf( stderr, "<INFO> waiting 20.0 seconds for a known call xaction to arrive (%ld)\n", time( NULL ) );
+ snprintf( msg->xaction, 17, "%015d", 5 ); // we'll reset receive counter before calling mt_call so this will arrive again
+ em_set_rcvcount( 0 );
+ msg = rmr_mt_call( rmc, msg, 2, 15000 ); // we need about 10s to get the message with the 'slow rate'
+ if( msg ) {
+ errors += fail_not_equal( msg->state, RMR_OK, "mt_call with known xaction id bad state (a)" );
+ } else {
+ errors += fail_if_nil( msg, "mt_call with known xaction id returned nil message" );
+ }
+ fprintf( stderr, "<INFO> time check: %ld\n", time( NULL ) );
+
+ em_set_mtc_msgs( 0 ); // turn off
+ em_set_rcvdelay( 0 ); // full speed receive rate to overflow the ring
+
+ fprintf( stderr, "<INFO> pausing 5s to allow mt-call receive ring to fill %ld\n", time( NULL ) );
+ sleep( 2 );
+ fprintf( stderr, "<INFO> tests continuing %ld\n", time( NULL ) );
+ em_set_rcvdelay( 1 ); // restore slow receive pace for any later tests
+ ((uta_ctx_t *)rmc)->shutdown = 1; // force the mt-reciver attached to the context to stop
+#endif
+
+
+ // --------------- phew, done ------------------------------------------------------------------------------
+
if( ! errors ) {
fprintf( stderr, "<INFO> all RMr API tests pass\n" );
}