From e15b1382dc618f6832957e67dc638b5e8f3f414d Mon Sep 17 00:00:00 2001 From: "E. Scott Daniels" Date: Tue, 14 Apr 2020 15:55:13 -0400 Subject: [PATCH] Fix rmr_call() parameter checking bug When RMR was extended to add wormhole support for a rmr_wh_call() function, the main call code was broken into an inward facing funciton. A parameter check which applies only to the outward facing rmr_call() API function was accidentally moved to the internal funciton. This change moves the check back into the rmr_call() funciton. Issue-ID: RIC-333 Signed-off-by: E. Scott Daniels Change-Id: Iab0c8cc33e8a9970c53b9248021a1273559f82f8 --- CHANGES_CORE.txt | 3 + CMakeLists.txt | 2 +- src/rmr/si/src/rmr_si.c | 17 +-- src/rmr/si/src/sr_si_static.c | 1 + test/lg_buf_static_test.c | 2 +- test/rmr_si_api_static_test.c | 146 +------------------------- test/rmr_si_rcv_static_test.c | 237 ++++++++++++++++++++++++++++++++++++++++++ test/rmr_si_rcv_test.c | 101 ++++++++++++++++++ test/rmr_si_test.c | 2 + test/test_msg_support.c | 94 +++++++++++++++++ test/test_si95_em.c | 66 +++++++++++- test/test_support.c | 2 +- 12 files changed, 518 insertions(+), 155 deletions(-) create mode 100644 test/rmr_si_rcv_static_test.c create mode 100644 test/rmr_si_rcv_test.c create mode 100644 test/test_msg_support.c diff --git a/CHANGES_CORE.txt b/CHANGES_CORE.txt index 3abf384..9500781 100644 --- a/CHANGES_CORE.txt +++ b/CHANGES_CORE.txt @@ -5,6 +5,9 @@ # API and build change and fix summaries. Doc correctsions # and/or changes are not mentioned here; see the commit messages. +2020 April 14; version 3.7.3 + Fix bug in rmr_call() when using SI95 (RIC-333) + 2020 April 10; version 3.7.2 Fix bug related to static route table only mode (RIC-331) diff --git a/CMakeLists.txt b/CMakeLists.txt index 8fcc274..a08762a 100644 --- a/CMakeLists.txt +++ b/CMakeLists.txt @@ -40,7 +40,7 @@ cmake_minimum_required( VERSION 3.5 ) set( major_version "3" ) # 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" ) diff --git a/src/rmr/si/src/rmr_si.c b/src/rmr/si/src/rmr_si.c index 7d7449f..4aefe4a 100644 --- a/src/rmr/si/src/rmr_si.c +++ b/src/rmr/si/src/rmr_si.c @@ -370,7 +370,7 @@ extern rmr_mbuf_t* rmr_call( void* vctx, rmr_mbuf_t* msg ) { return msg; } - return rmr_mt_call( vctx, msg, 1, 1000 ); // use the reserved call-id of 1 and wait up to 1 sec + return mt_call( vctx, msg, 1, 1000, NULL ); // use the reserved call-id of 1 and wait up to 1 sec } /* @@ -874,6 +874,7 @@ extern rmr_mbuf_t* rmr_mt_rcv( void* vctx, rmr_mbuf_t* mbuf, int max_wait ) { if( mbuf != NULL ) { mbuf->flags |= MFL_ADDSRC; // turn on so if user app tries to send this buffer we reset src } + return mbuf; } @@ -974,12 +975,6 @@ static rmr_mbuf_t* mt_call( void* vctx, rmr_mbuf_t* mbuf, int call_id, int max_w return mbuf; } - if( call_id > MAX_CALL_ID || call_id < 2 ) { // 0 and 1 are reserved; user app cannot supply them - mbuf->state = RMR_ERR_BADARG; - mbuf->tp_state = errno; - return mbuf; - } - ombuf = mbuf; // save to return timeout status with chute = &ctx->chutes[call_id]; @@ -1081,6 +1076,14 @@ static rmr_mbuf_t* mt_call( void* vctx, rmr_mbuf_t* mbuf, int call_id, int max_w This is now just an outward facing wrapper so we can support wormhole calls. */ extern rmr_mbuf_t* rmr_mt_call( void* vctx, rmr_mbuf_t* mbuf, int call_id, int max_wait ) { + + // must vet call_id here, all others vetted by workhorse mt_call() function + if( call_id > MAX_CALL_ID || call_id < 2 ) { // 0 and 1 are reserved; user app cannot supply them + mbuf->state = RMR_ERR_BADARG; + mbuf->tp_state = EINVAL; + return mbuf; + } + return mt_call( vctx, mbuf, call_id, max_wait, NULL ); } diff --git a/src/rmr/si/src/sr_si_static.c b/src/rmr/si/src/sr_si_static.c index dac0cb5..798fe26 100644 --- a/src/rmr/si/src/sr_si_static.c +++ b/src/rmr/si/src/sr_si_static.c @@ -789,6 +789,7 @@ static rmr_mbuf_t* mtosend_msg( void* vctx, rmr_mbuf_t* msg, int max_to ) { } else { ok_sends++; msg = clone_m; // clone will be the next to send + msg->state = RMR_OK; } } else { msg = send_msg( ctx, msg, nn_sock, max_to ); // send the last, and allocate a new buffer; drops the clone if it was diff --git a/test/lg_buf_static_test.c b/test/lg_buf_static_test.c index a74e080..35c3be8 100644 --- a/test/lg_buf_static_test.c +++ b/test/lg_buf_static_test.c @@ -59,7 +59,7 @@ static int rmr_lgbuf_test( ) { snprintf( msg->payload, msg->len, "Rambling Wreck from Georgia Tech!\n\n" ); msg = rmr_send_msg( rmc, msg ); if( msg && msg->state != RMR_OK ) { - printf( stderr, "[ERR] lg buf test: send failed? %d\n", msg->state ); + fprintf( stderr, " lg buf test: send failed? %d\n", msg->state ); } rmr_free_msg( msg ); diff --git a/test/rmr_si_api_static_test.c b/test/rmr_si_api_static_test.c index e50a987..528e9cc 100644 --- a/test/rmr_si_api_static_test.c +++ b/test/rmr_si_api_static_test.c @@ -45,6 +45,10 @@ rmr_mtosend_msg rmr_free_msg + Not all message/call functions can be tested here because of the + callback nature of SI. There is a specific rcv test static module + for those tests. + Author: E. Scott Daniels Date: 5 April 2019 */ @@ -62,45 +66,6 @@ #include "rmr.h" #include "rmr_agnostic.h" -/* - Send a 'burst' of messages to drive some send retry failures to increase RMr coverage - by handling the retry caee. -*/ -static void send_n_msgs( void* ctx, int n ) { - rmr_mbuf_t* msg; // message buffers - int i; - - msg = rmr_alloc_msg( ctx, 1024 ); - if( ! msg ) { - return; - } - - for( i = 0; i < n; i++ ) { - //fprintf( stderr, "mass send\n" ); - msg->len = 100; - msg->mtype = 1; - msg->state = 999; - errno = 999; - msg = rmr_send_msg( ctx, msg ); - } -} - -/* - 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 @@ -265,109 +230,6 @@ static int rmr_api_test( ) { mt_disc_cb( rmc, 0 ); // disconnect callback for coverage mt_disc_cb( rmc, 100 ); // with a fd that doesn't exist -return errors; - - msg2 = rmr_rcv_msg( NULL, NULL ); - errors += fail_if( msg2 != NULL, "rmr_rcv_msg returned msg when given nil context and msg " ); - - msg2 = rmr_rcv_msg( rmc, NULL ); - errors += fail_if( msg2 == NULL, "rmr_rcv_msg returned nil msg when given nil msg " ); - if( msg2 ) { - 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) " ); - } - } - - - msg = rmr_rcv_msg( rmc, msg ); - if( msg ) { - errors += fail_not_equal( msg->state, RMR_OK, "rmr_rcv_msg did not return an ok state " ); - errors += fail_not_equal( msg->len, 220, "rmr_rcv_msg returned message with invalid len " ); - } else { - errors += fail_if_nil( msg, "rmr_rcv_msg returned a nil pointer " ); - } - - rmr_rts_msg( NULL, NULL ); // drive for coverage - rmr_rts_msg( rmc, NULL ); - errors += fail_if( errno == 0, "rmr_rts_msg did not set errno when given a nil message " ); - - msg->state = 0; - msg = rmr_rts_msg( NULL, msg ); // should set state in msg - 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_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)" ); - - 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->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 ); // 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 - break; - } - fprintf( stderr, " msg: %s\n", msg->xaction ); - } else { - errors += fail_if_nil( msg, "receive returnd nil msg while looking for queued message " ); - } - } - - errors += fail_if( i >= 16, "did not find expected message on queue " ); - - if( ! msg ) { - msg = rmr_alloc_msg( rmc, 2048 ); // something buggered above; get a new one - } - 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 - rmr_free_msg( msg2 ); - - - msg2 = rmr_torcv_msg( NULL, NULL, 10 ); - errors += fail_not_nil( msg2, "rmr_torcv_msg returned a pointer when given nil information " ); - msg2 = rmr_torcv_msg( rmc, NULL, 10 ); - errors += fail_if_nil( msg2, "rmr_torcv_msg did not return a message pointer when given a nil old msg " ); - - // --- test timeout receive; our dummy epoll function will return 1 ready on first call and 0 ready (timeout emulation) on second - // however we must drain the swamp (queue) first, so run until we get a timeout error, or 20 and report error if we get to 20. - msg = NULL; - for( i = 0; i < 40; i++ ) { - msg = rmr_torcv_msg( rmc, msg, 10 ); - errors += fail_if_nil( msg, "torcv_msg returned nil msg when message expected " ); - if( msg ) { - if( msg->state == RMR_ERR_TIMEOUT || msg->state == RMR_ERR_EMPTY ) { // queue drained and we've seen both states from poll if we get a timeout - break; - } - } - } - 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 ------- state = rmr_init_trace( NULL, 37 ); // coverage test nil context diff --git a/test/rmr_si_rcv_static_test.c b/test/rmr_si_rcv_static_test.c new file mode 100644 index 0000000..ad543a0 --- /dev/null +++ b/test/rmr_si_rcv_static_test.c @@ -0,0 +1,237 @@ +// : vi ts=4 sw=4 noet : +/* +================================================================================== + Copyright (c) 2019-2020 Nokia + Copyright (c) 2018-2020 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. +================================================================================== +*/ + +/* + Mmemonic: rmr_si_api_static_test.c + Abstract: Specific tests related to the API functions in rmr_si.c. + This should be included by a driver which invokes the 'main' + test function here: rmr_api_test. + + This test set applies only to the outward facting API functions + in the rmr_si.c module (mostly because the context for SI is + different). + + The message buffer specific API tests are in a different static + module. API functions tested here are: + rmr_close + rmr_get_rcvfd + rmr_ready + rmr_init + rmr_set_rtimeout + rmr_set_stimeout + rmr_rcv_specific + rmr_torcv_msg + rmr_rcv_msg + rmr_call + rmr_rts_msg + rmr_send_msg + rmr_mtosend_msg + rmr_free_msg + + Author: E. Scott Daniels + Date: 14 April 2020 (AKD) +*/ + +#define DEBUG 2 + +#include +#include +#include +#include +#include +#include +#include +#include +#include + +#include "rmr.h" +#include "rmr_agnostic.h" + +static int rmr_rcv_test( ) { + int errors = 0; + void* rmc; // route manager context + void* rmc2; // second context for non-listener init + rmr_mbuf_t* msg; // message buffers + rmr_mbuf_t* msg2; + int v = 0; // some value + char wbuf[128]; + int i; + int state; + int max_tries; // prevent a sticking in any loop + + 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; + } + + 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 " ); + gen_rt( rmc ); // gen dummy route table + + if( ! rmr_ready( rmc ) ) { + fprintf( stderr, "\nPANIC! rmr isn't showing ready after loading a rt table\n\n" ); + return errors+1; + } + + msg = rmr_alloc_msg( rmc, 2048 ); // get a buffer with a transport header + msg->len = 500; + msg->mtype = 1; + msg->state = 999; + msg->tp_state = 999; + errno = 999; + snprintf( msg->payload, 500, "Stand up and cheer from OU to Oh yea! (5)" ); + + 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_OK, "send_msg returned bad status for send that should work " ); + 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 ); // not supported, but funciton exists, so drive away + rmr_set_stimeout( rmc, 20 ); + rmr_set_stimeout( rmc, -1 ); + rmr_set_rtimeout( NULL, 0 ); + rmr_set_rtimeout( rmc, 20 ); + rmr_set_rtimeout( rmc, -1 ); + + max_tries = 10; // there shouldn't be more than 10 queued at this point + while( (msg2 = rmr_torcv_msg( rmc, msg2, 200 )) != NULL ) { + if( msg2->state != RMR_OK || max_tries <= 0 ) { + break; + } + + max_tries--; + } + + msg2 = rmr_rcv_msg( NULL, NULL ); + errors += fail_if( msg2 != NULL, "rmr_rcv_msg returned msg when given nil context and msg " ); + + send_n_msgs( rmc, 1 ); // ensure there is a message to read + msg2 = rmr_rcv_msg( rmc, NULL ); + errors += fail_if( msg2 == NULL, "rmr_rcv_msg returned nil msg when given nil msg " ); + if( msg2 ) { + 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) " ); + } + } + + send_n_msgs( rmc, 1 ); // ensure there is a message to read (len is set to 100) + msg = rmr_rcv_msg( rmc, msg ); + if( msg ) { + errors += fail_not_equal( msg->state, RMR_OK, "rmr_rcv_msg did not return an ok state " ); + errors += fail_not_equal( msg->len, 100, "rmr_rcv_msg returned message with invalid len " ); + } else { + errors += fail_if_nil( msg, "rmr_rcv_msg returned a nil pointer " ); + } + + rmr_rts_msg( NULL, NULL ); // drive for coverage + rmr_rts_msg( rmc, NULL ); + errors += fail_if( errno == 0, "rmr_rts_msg did not set errno when given a nil message " ); + + msg->state = 0; + msg = rmr_rts_msg( NULL, msg ); // should set state in msg + 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_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)" ); + + 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 " ); + + em_set_rcvcount( 0 ); // reset message counter + em_set_rcvdelay( 1 ); // force slow msg rate during mt testing + em_disable_call_flg(); // cause reflected message to appear to be a response + + snprintf( msg->xaction, 17, "%015d", 16 ); + msg->mtype = 0; + msg->sub_id = -1; + msg->len = 234; + msg = rmr_call( rmc, msg ); + 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 " ); + } + + if( ! msg ) { + msg = rmr_alloc_msg( rmc, 2048 ); // something buggered above; get a new one + } + + em_allow_call_flg(); // cause reflected message to appear to be a call + snprintf( msg->xaction, 17, "%015d", 16 ); // ensure there is an xaction id + msg->mtype = 0; + msg->sub_id = -1; + msg->len = 345; + 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 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 + rmr_free_msg( msg2 ); + + msg2 = rmr_torcv_msg( NULL, NULL, 10 ); + errors += fail_not_nil( msg2, "rmr_torcv_msg returned a pointer when given nil information " ); + msg2 = rmr_torcv_msg( rmc, NULL, 10 ); + errors += fail_if_nil( msg2, "rmr_torcv_msg did not return a message pointer when given a nil old msg " ); + + // --- test timeout receive; our dummy epoll function will return 1 ready on first call and 0 ready (timeout emulation) on second + // however we must drain the swamp (queue) first, so run until we get a timeout error, or 20 and report error if we get to 20. + msg = NULL; + for( i = 0; i < 40; i++ ) { + msg = rmr_torcv_msg( rmc, msg, 10 ); + errors += fail_if_nil( msg, "torcv_msg returned nil msg when message expected " ); + if( msg ) { + if( msg->state == RMR_ERR_TIMEOUT || msg->state == RMR_ERR_EMPTY ) { // queue drained and we've seen both states from poll if we get a timeout + break; + } + } + } + errors += fail_if( i >= 40, "torcv_msg never returned a timeout " ); + + ((uta_ctx_t *)rmc)->shutdown = 1; + rmr_close( NULL ); // drive for coverage + rmr_close( rmc ); // no return to check; drive for coverage + + + // --------------- phew, done ------------------------------------------------------------------------------ + + if( ! errors ) { + fprintf( stderr, " all RMR receive tests pass\n" ); + } else { + fprintf( stderr, " receive tests failures noticed \n" ); + } + + return !!errors; +} diff --git a/test/rmr_si_rcv_test.c b/test/rmr_si_rcv_test.c new file mode 100644 index 0000000..fdd1f33 --- /dev/null +++ b/test/rmr_si_rcv_test.c @@ -0,0 +1,101 @@ +// :vi sw=4 ts=4 noet: +/* +================================================================================== + Copyright (c) 2020 Nokia + Copyright (c) 2020 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. +================================================================================== +*/ + +/* + Mmemonic: rmr_si_rcv_test.c + Abstract: This drives only the receive tests for the SI API. Because + of the threaded nature of SI receives it is not possible to + mix these tests with the other coverage tests which allocate + various contexes. + + Author: E. Scott Daniels + Date: 14 April 2020 (AKD) +*/ + +#include +#include +#include +#include +#include +#include +#include +#include + + +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include + +#define DEBUG 1 +#define PARANOID_CHECKS 1 // must have parinoid testing on to not fail on nil pointer tests + + // specific test tools in this directory +#undef NNG_UNDER_TEST +#include "test_support.c" // things like fail_if() +#include "test_ctx_support.c" // dummy context support +#include "test_msg_support.c" +#include "test_gen_rt.c" + + +#include "rmr.h" // things the users see +#include "rmr_symtab.h" +#include "rmr_logging.h" +#include "rmr_agnostic.h" // transport agnostic header + +#include "symtab.c" +#include "logging.c" +#include "rmr_si.c" +#include "mbuf_api.c" + + +static void gen_rt( uta_ctx_t* ctx ); // defined in sr_si_static_test, but used by a few others (eliminate order requirement below) + + // and finally.... +#include "rmr_si_rcv_static_test.c" // the only test driver + + +/* + Drive each of the separate tests and report. +*/ +int main() { + int errors = 0; + + rmr_set_vlevel( 5 ); // enable all debugging + + fprintf( stderr, "\n starting receive tests (%d)\n", errors ); + errors += rmr_rcv_test(); + fprintf( stderr, " error count: %d\n", errors ); + + if( errors == 0 ) { + fprintf( stderr, " all tests were OK\n\n" ); + } else { + fprintf( stderr, " %d modules reported errors\n\n", errors ); + } + + return !!errors; +} diff --git a/test/rmr_si_test.c b/test/rmr_si_test.c index aa1b6ab..c3eb09b 100644 --- a/test/rmr_si_test.c +++ b/test/rmr_si_test.c @@ -61,6 +61,7 @@ #undef NNG_UNDER_TEST #include "test_support.c" // things like fail_if() #include "test_ctx_support.c" // dummy context support +#include "test_msg_support.c" #include "test_gen_rt.c" @@ -86,6 +87,7 @@ static void gen_rt( uta_ctx_t* ctx ); // defined in sr_si_static_test, but used #include "mbuf_api_static_test.c" #include "sr_si_static_test.c" #include "lg_buf_static_test.c" +// do NOT include the receive test static must be stand alone #include "rmr_si_api_static_test.c" diff --git a/test/test_msg_support.c b/test/test_msg_support.c new file mode 100644 index 0000000..1e52c83 --- /dev/null +++ b/test/test_msg_support.c @@ -0,0 +1,94 @@ +// vi: ts=4 sw=4 noet : +/* +================================================================================== + Copyright (c) 2019-2020 Nokia + Copyright (c) 2018-2020 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: test_msg_support.c + Abstract: Support for testing with messages; requires RMR defs, so not + to be included for things like ring tests etc. + Author: E. Scott Daniels + Date: 14 April 2020 (AKD) +*/ + +#ifndef _test_msg_support_c +#define _test_msg_support_c + +#include +#include +#include +#include +#include +#include + +int test_support_xact_count = 0; +/* + Send a 'burst' of messages to drive some send retry failures to increase RMr coverage + by handling the retry caee. +*/ +static void send_n_msgs( void* ctx, int n ) { + rmr_mbuf_t* msg; // message buffers + int i; + + msg = rmr_alloc_msg( ctx, 1024 ); + if( ! msg ) { + fprintf( stderr, " mass send of %d messages couldn't allocate message!\n", n ); + return; + } + + fprintf( stderr, " mass send of %d messages\n", n ); + for( i = 0; i < n; i++ ) { + msg->len = 100; + msg->mtype = 1; + msg->state = 999; + + snprintf( msg->xaction, 32, "%015d", test_support_xact_count++ ); // simple transaction id so we can test receive specific and ring stuff + + errno = 999; + msg = rmr_send_msg( ctx, msg ); + if( msg && msg->state != 0 ) { + fprintf( stderr, " mass send failed: state=%d type=%d\n", msg->state, msg->mtype ); + } + } +} + + +/* + Allow test to reset the transaction id counter. +*/ +static void reset_xact_count() { + test_support_xact_count = 0; +} + +/* + 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; +} + +#endif diff --git a/test/test_si95_em.c b/test/test_si95_em.c index c2cf4cb..9eb7d94 100644 --- a/test/test_si95_em.c +++ b/test/test_si95_em.c @@ -32,7 +32,7 @@ #include "rmr.h" // we use some of rmr defs in building dummy messages, so we need these #include "rmr_agnostic.h" -// ---------------------- emulated nng functions --------------------------- +// ---------------------- emulated SI95 functions --------------------------- #ifndef _em_si // this is the same define as the nng emulation code uses to give warning if both included @@ -43,6 +43,37 @@ #include "test_common_em.c" // common emulation needed for all (epoll, gethostname...) +// --- some globals -------------------------------------------------------- +int em_reset_call_flag = 0; // allows a send to turn off the call flag (see em_disable_call_flg()) + +// ------------- emulated message header ----------------------------------- + +/* + This is a copy from agnostic.h. we need to reset flags in some situations + so we have to have this, under a different name to avoid disaster. +*/ +typedef struct { + int32_t mtype; // message type ("long" network integer) + int32_t plen; // payload length (sender data length in payload) + int32_t rmr_ver; // our internal message version number + unsigned char xid[RMR_MAX_XID]; // space for user transaction id or somesuch + unsigned char sid[RMR_MAX_SID]; // sender ID for return to sender needs + unsigned char src[RMR_MAX_SRC]; // name:port of the sender (source) + unsigned char meid[RMR_MAX_MEID]; // managed element id. + struct timespec ts; // timestamp ??? + + // V2 extension + int32_t flags; // HFL_* constants + int32_t len0; // length of the RMr header data + int32_t len1; // length of the tracing data + int32_t len2; // length of data 1 (d1) + int32_t len3; // length of data 2 (d2) + int32_t sub_id; // subscription id (-1 invalid) + + // v3 extension + unsigned char srcip[RMR_MAX_SRC]; // ip address and port of the source +} em_mhdr_t; + //-------------------------------------------------------------------------- /* These are the current references in the RMR code; all others are internal @@ -123,8 +154,10 @@ static int em_siconnect( struct ginfo_blk *gptr, char *abuf ) { return -1; } - fprintf( stderr, " siem is emulating connect attempt return fd=%d\n", em_next_fd ); - em_next_fd++; + fprintf( stderr, " siem is emulating connect to (%s) attempt return fd=%d\n", abuf, em_next_fd ); + if( em_next_fd < 50 ) { + em_next_fd++; + } return em_next_fd-1; } @@ -171,8 +204,28 @@ static void em_sisend( struct ginfo_blk *gptr, struct tp_blk *tpptr ) { return; } +/* + Calling this function causes the send emulation to turn off the call + flag in the RMR header. Turning that flag off makes the arriving message + look as though it might be a response to a call rather than a call itself. + This is needed since we loop back messages. +*/ +static void em_disable_call_flg() { + em_reset_call_flag = 1; + fprintf( stderr, " reset call flag setting is: %d\n", em_reset_call_flag ); +} + +/* + Opposite of disable_call_flg; the flag is not touched. +*/ +static void em_allow_call_flg() { + em_reset_call_flag = 0; + fprintf( stderr, " reset call flag setting is: %d\n", em_reset_call_flag ); +} + // callback prototype to drive to simulate 'receive' static int mt_data_cb( void* datap, int fd, char* buf, int buflen ); + /* Emulate sending a message. If the global em_send_failures is set, then every so often we fail with an EAGAIN to drive that part @@ -191,6 +244,13 @@ static int em_sisendt( struct ginfo_blk *gptr, int fd, char *ubuf, int ulen ) { return SIEM_BLOCKED; } + if( em_reset_call_flag ) { // for call testing we need to flip the flag off to see it "return" + em_mhdr_t* hdr; + + hdr = (em_mhdr_t *) (ubuf+50); // past the transport header bytes + hdr->flags &= ~HFL_CALL_MSG; // flip off the call flag + } + uss++; if( em_cb_data != NULL ) { diff --git a/test/test_support.c b/test/test_support.c index 8429e50..9f8f00f 100644 --- a/test/test_support.c +++ b/test/test_support.c @@ -1,4 +1,4 @@ -// : vi ts=4 sw=4 noet : +// vi: ts=4 sw=4 noet : /* ================================================================================== Copyright (c) 2019-2020 Nokia -- 2.16.6