From fc2112d22bf69b4bfbe0c419ed366f0d0ec370ca Mon Sep 17 00:00:00 2001 From: "E. Scott Daniels" Date: Tue, 21 Apr 2020 12:51:05 -0400 Subject: [PATCH] Remove NNG libraries from packages The default build process will no longer include the NNG libraries (librmr_nng.*) by default. It is still possible to enable them with a CMake build flag (-DBUILD_NNG=1). The NNG specific unit tests have been disabled. Some SI95 specific unit tests have been enhanced in an effort to work toward full coverage of the SI95 code. This change is in a major version bump as the package contents change. However, there is NOT an API change; all existing applications will be able to use the new version without any modification (other than possibly removing references to the NNG based libraries). Issue-ID: RIC-337 Signed-off-by: E. Scott Daniels Change-Id: Ic9854b1ffc1e82c765692a11724d8086d24cceed --- CHANGES_CORE.txt | 11 ++ CMakeLists.txt | 189 ++++++++++++++++------------- src/rmr/common/include/RIC_message_types.h | 16 ++- src/rmr/common/src/rtc_static.c | 174 +++++++++++++++----------- src/rmr/si/src/mt_call_si_static.c | 4 +- src/rmr/si/src/rmr_si.c | 43 ++++--- test/Makefile | 4 +- test/rmr_si_api_static_test.c | 16 ++- test/rmr_si_rcv_static_test.c | 37 ++++++ test/rt_static_test.c | 31 +++++ test/si95_test.c | 20 +-- test/sr_si_static_test.c | 38 ++++-- test/test_ctx_support.c | 4 +- test/unit_test.ksh | 38 +++--- 14 files changed, 400 insertions(+), 225 deletions(-) diff --git a/CHANGES_CORE.txt b/CHANGES_CORE.txt index 89d0595..481452c 100644 --- a/CHANGES_CORE.txt +++ b/CHANGES_CORE.txt @@ -5,6 +5,17 @@ # API and build change and fix summaries. Doc correctsions # and/or changes are not mentioned here; see the commit messages. +2020 April 21; version 4.0.0 + The NNG based libraries are no longer included in the RMR packages. + This is considered a breaking change as NNG will not be supported by + default. It is still possible to build with RMR-NNG libraries, but + that is the exception. The API between 3.8.2 and 4.0.0 is the SAME. + Upgrading to 4.0.0 only means that the underlying transport mechanism + is limited only to SI95. + + The rmr_rcv_specific() function has been deprecated as it was necessary + only for NNG and Nanomsg support. Its use should be discontinued. + 2020 April 20; version 3.8.2 Fix bug which was preventing an instance receiving dynamic route table updates. (RIC-336) diff --git a/CMakeLists.txt b/CMakeLists.txt index 3109513..a8aa1ba 100644 --- a/CMakeLists.txt +++ b/CMakeLists.txt @@ -22,6 +22,7 @@ # -DDEBUG=n Enable debugging level n # -DDEV_PKG=1 Development package configuration # -DBUILD_DOC=1 Man pages generated +# -DBUILD_NNG=1 Enable building of NNG and the RMR NNG based libraries # -DIGNORE_LIBDIR=1 Installation of rmr libries is into /usr/local/lib and ignores # value in CMAKE_INSTALL_LIBDIR. # system preferred (typically /usr/local/lib64). @@ -38,9 +39,9 @@ project( rmr LANGUAGES C ) 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 "8" ) -set( patch_level "2" ) +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 "0" ) +set( patch_level "0" ) set( install_root "${CMAKE_INSTALL_PREFIX}" ) set( install_inc "include/rmr" ) @@ -50,11 +51,10 @@ else() set( install_man "/usr/share/man" ) # this needs to be fixed so it's not hard coded endif() -# Must use GNUInstallDirs to install libraries into correct -# locations on all platforms. +# Must use GNUInstallDirs to install libraries into correct locations on all platforms. include( GNUInstallDirs ) -# nng installs using LIBDIR as established by the gnu include; it varies from system +# We install using LIBDIR as established by the gnu include; it varies from system # to system, and we don't trust that it is always set, so we default to lib if it is missing. # if( NOT CMAKE_INSTALL_LIBDIR ) @@ -165,56 +165,60 @@ else() endif() # ---------------- setup nano/nng things --------------------------------------- -if( NOT SKIP_EXTERNALS ) - set( need_ext 1 ) # we force dependences on these for right build order - execute_process( COMMAND git submodule update --init -- ext/nng - WORKING_DIRECTORY ${CMAKE_CURRENT_SOURCE_DIR} - ) - - if( NOT EXISTS ${CMAKE_CURRENT_SOURCE_DIR}/ext/nng/CMakeLists.txt ) - message( FATAL_ERROR "cannot find nng in our git source as a submodule: Giving up" ) # this will abort which seems wrong, but tdam. - endif() - - include( ExternalProject ) - ExternalProject_Add( - ext_nng - SOURCE_DIR "${CMAKE_CURRENT_SOURCE_DIR}/ext/nng" - CMAKE_ARGS "-DBUILD_SHARED_LIBS=1" - CMAKE_ARGS "-DCMAKE_INSTALL_PREFIX=${CMAKE_CURRENT_BINARY_DIR}" - BUILD_COMMAND "make" - UPDATE_COMMAND "" - TEST_COMMAND "" - STEP_TARGETS build - ) - - # it seems impossible to install everything that lands in {bin}/lib, so we need to - # hard code (shudder) some things. Even worse, we have to make exceptions for - # builds on apple (osx) since their naming convention wandered off the path. - set( nng_major 1 ) - set( nng_minor 1.0 ) - set( so ${CMAKE_SHARED_LIBRARY_SUFFIX} ) # cmake variables are impossibly long :( - if( NOT APPLE ) # probably breaks in windows, but idc - set( nng_so_suffix ${so} ) - set( nng_so_suffix_m ${so}.${nng_major} ) - set( nng_so_suffix_mm ${so}.${nng_major}.${nng_minor} ) - else() - # of course apple puts versions before the suffix :( - set( nng_so_suffix ${so} ) # so has a lead dot, so NOT needed - set( nng_so_suffix_m ".${nng_major}${so}" ) # these need leading dots - set( nng_so_suffix_mm ".${nng_major}.${nng_minor}${so}" ) - endif() - - message( "+++ building with nng: ${nng_major}.${nng_minor}" ) +if( NOT BUILD_NNG ) + set( PACK_EXTERNALS 0 ) else() - if( PACK_EXTERNALS ) - # This makes some stand-alone unit testing possible for bindings and transport layer testing; - # it is not meant for production packages. - # - unset( SKIP_EXTERNALS CACHE ) # must remove so as not to trap user into a never ending failure - unset( PACK_EXTERNALS CACHE ) - message( FATAL_ERROR "ERROR: PACK_EXTERNALS can be set only if SKIP_EXTERNALS is unset (=0, or not supplied on command line)" ) + if( NOT SKIP_EXTERNALS ) + set( need_ext 1 ) # we force dependences on these for right build order + execute_process( COMMAND git submodule update --init -- ext/nng + WORKING_DIRECTORY ${CMAKE_CURRENT_SOURCE_DIR} + ) + + if( NOT EXISTS ${CMAKE_CURRENT_SOURCE_DIR}/ext/nng/CMakeLists.txt ) + message( FATAL_ERROR "cannot find nng in our git source as a submodule: Giving up" ) # this will abort which seems wrong, but tdam. + endif() + + include( ExternalProject ) + ExternalProject_Add( + ext_nng + SOURCE_DIR "${CMAKE_CURRENT_SOURCE_DIR}/ext/nng" + CMAKE_ARGS "-DBUILD_SHARED_LIBS=1" + CMAKE_ARGS "-DCMAKE_INSTALL_PREFIX=${CMAKE_CURRENT_BINARY_DIR}" + BUILD_COMMAND "make" + UPDATE_COMMAND "" + TEST_COMMAND "" + STEP_TARGETS build + ) + + # it seems impossible to install everything that lands in {bin}/lib, so we need to + # hard code (shudder) some things. Even worse, we have to make exceptions for + # builds on apple (osx) since their naming convention wandered off the path. + set( nng_major 1 ) + set( nng_minor 1.0 ) + set( so ${CMAKE_SHARED_LIBRARY_SUFFIX} ) # cmake variables are impossibly long :( + if( NOT APPLE ) # probably breaks in windows, but idc + set( nng_so_suffix ${so} ) + set( nng_so_suffix_m ${so}.${nng_major} ) + set( nng_so_suffix_mm ${so}.${nng_major}.${nng_minor} ) + else() + # of course apple puts versions before the suffix :( + set( nng_so_suffix ${so} ) # so has a lead dot, so NOT needed + set( nng_so_suffix_m ".${nng_major}${so}" ) # these need leading dots + set( nng_so_suffix_mm ".${nng_major}.${nng_minor}${so}" ) + endif() + + message( "+++ building with nng: ${nng_major}.${nng_minor}" ) + else() + if( PACK_EXTERNALS ) + # This makes some stand-alone unit testing possible for bindings and transport layer testing; + # it is not meant for production packages. + # + unset( SKIP_EXTERNALS CACHE ) # must remove so as not to trap user into a never ending failure + unset( PACK_EXTERNALS CACHE ) + message( FATAL_ERROR "ERROR: PACK_EXTERNALS can be set only if SKIP_EXTERNALS is unset (=0, or not supplied on command line)" ) + endif() + set( need_ext 0 ) endif() - set( need_ext 0 ) endif() @@ -243,30 +247,34 @@ unset( GPROF CACHE ) # we don't want this to persist # Include modules add_subdirectory( src/rmr/common ) -add_subdirectory( src/rmr/nng ) +if( BUILD_NNG ) + add_subdirectory( src/rmr/nng ) +endif() add_subdirectory( src/rmr/si ) add_subdirectory( doc ) # this will auto skip if {X}fm is not available # shared and static libraries are built from the same object files. -# librmr_nng is a combination of common and nng specific rmr functions. +# librmr_* is a combination of common and * specific rmr functions. # -add_library( rmr_nng_shared SHARED "$;$" ) -set_target_properties( rmr_nng_shared - PROPERTIES - OUTPUT_NAME "rmr_nng" - SOVERSION ${major_version} - VERSION ${major_version}.${minor_version}.${patch_level} ) - -# we only build/export the static archive (.a) if generating a dev package -if( DEV_PKG ) - add_library( rmr_nng_static STATIC "$;$" ) - set_target_properties( rmr_nng_static +if( BUILD_NNG ) + add_library( rmr_nng_shared SHARED "$;$" ) + set_target_properties( rmr_nng_shared PROPERTIES OUTPUT_NAME "rmr_nng" SOVERSION ${major_version} VERSION ${major_version}.${minor_version}.${patch_level} ) + + # we only build/export the static archive (.a) if generating a dev package + if( DEV_PKG ) + add_library( rmr_nng_static STATIC "$;$" ) + set_target_properties( rmr_nng_static + PROPERTIES + OUTPUT_NAME "rmr_nng" + SOVERSION ${major_version} + VERSION ${major_version}.${minor_version}.${patch_level} ) + endif() endif() add_library( rmr_si_shared SHARED "$;$" ) @@ -276,7 +284,7 @@ set_target_properties( rmr_si_shared SOVERSION ${major_version} VERSION ${major_version}.${minor_version}.${patch_level} ) -# even if not generating a development package we still need to generate the .a so that health check +# even if not generating a development package we still need to generate the .a so that health check # can link against it to avoid RPM install issues. # add_library( rmr_si_static STATIC "$;$" ) @@ -286,12 +294,14 @@ set_target_properties( rmr_si_static SOVERSION ${major_version} VERSION ${major_version}.${minor_version}.${patch_level} ) -# if externals need to be built, then we must force them to be built first by depending on them -if( need_ext ) - if( DEV_PKG ) - add_dependencies( rmr_nng_shared;rmr_nng_static ext_nng ) - else() - add_dependencies( rmr_nng_shared ext_nng ) +if( BUILD_NNG ) + # if externals need to be built, then we must force them to be built first by depending on them + if( need_ext ) + if( DEV_PKG ) + add_dependencies( rmr_nng_shared;rmr_nng_static ext_nng ) + else() + add_dependencies( rmr_nng_shared ext_nng ) + endif() endif() endif() @@ -319,32 +329,43 @@ add_subdirectory( src/support ) # ------------- packaging ----------------------------------------------------- # -if( APPLE ) - message( "### apple hack: forcing hard coded library paths for nng/nano dynamic libraries" ) - target_link_libraries( rmr_nng_shared ${CMAKE_CURRENT_BINARY_DIR}/lib/libnng${nng_so_suffix} ) +if( BUILD_NNG ) + if( APPLE ) + message( "### apple hack: forcing hard coded library paths for nng/nano dynamic libraries" ) + target_link_libraries( rmr_nng_shared ${CMAKE_CURRENT_BINARY_DIR}/lib/libnng${nng_so_suffix} ) + endif() endif() # Define what should be installed, and where they should go. For dev package we install # only the RMr headers, man pages and archive (.a) files. The run-time package gets just # the library (.so) files and nothing more. # -if( DEV_PKG ) - set( target_list "rmr_nng_static;rmr_si_static" ) +if( BUILD_NNG ) + if( DEV_PKG ) + set( target_list "rmr_nng_static;rmr_si_static" ) + else() + set( target_list "rmr_nng_shared;rmr_si_shared" ) + endif() else() - set( target_list "rmr_nng_shared;rmr_si_shared" ) + if( DEV_PKG ) + set( target_list "rmr_si_static" ) + else() + set( target_list "rmr_si_shared" ) + endif() endif() install( TARGETS ${target_list} EXPORT LibraryConfig - LIBRARY DESTINATION ${install_lib} - ARCHIVE DESTINATION ${install_lib} - PUBLIC_HEADER DESTINATION ${install_inc} + LIBRARY DESTINATION ${install_lib} + ARCHIVE DESTINATION ${install_lib} + PUBLIC_HEADER DESTINATION ${install_inc} ) unset( DEV_PKG CACHE ) # prevent from being a hidden setting if user redoes things # install any nano/nng libraries in to the deb as well, but ONLY if asked for on the 'cmake ..' command -# (sure would be nice if FILEs allowed for globbing; sadly it does not.) +# (sure would be nice if FILEs allowed for globbing; sadly it does not.) Disabled by default if BUILD_NNG +# is turned off. # if( PACK_EXTERNALS ) message( "+++ including nano and nng libraries in the deb" ) diff --git a/src/rmr/common/include/RIC_message_types.h b/src/rmr/common/include/RIC_message_types.h index 03b212b..d28fe42 100644 --- a/src/rmr/common/include/RIC_message_types.h +++ b/src/rmr/common/include/RIC_message_types.h @@ -20,19 +20,19 @@ -/* +/* Header file defining message types for various RMR messages */ #define RIC_UNDEFINED -1 -/* +/* --------------------------------------------------------- RMR Reserved types All message types 0 - 99 are reserved for RMM. --------------------------------------------------------- */ - + #define RMRRM_TABLE_DATA 20 // table data from route manger #define RMRRM_REQ_TABLE 21 // request for table update to route mangager #define RMRRM_TABLE_STATE 22 // state of table to route mgr @@ -147,19 +147,23 @@ #define DC_ADM_GET_POLICY 20002 #define DC_ADM_GET_POLICY_ACK 20003 -#define A1_POLICY_REQ 20010 -#define A1_POLICY_RESP 20011 +#define A1_POLICY_REQ 20010 +#define A1_POLICY_RESP 20011 #define A1_POLICY_QUERY 20012 // --- application specific message numbers 30000 - 39999 - + #define TS_UE_LIST 30000 // traffic steering #define TS_QOE_PRED_REQ 30001 #define TS_QUE_PREDICTION 30002 #define MC_REPORT 30010 // Measurement campaign xApp reports +#define DCAPTERM_RTPM_RMR_MSGTYPE 33001 +#define DCAPTERM_GEO_RMR_MSGTYPE 33002 + + // ---- these are old (release 0) definitions and should not be used ------ diff --git a/src/rmr/common/src/rtc_static.c b/src/rmr/common/src/rtc_static.c index 5fdf064..03f9db0 100644 --- a/src/rmr/common/src/rtc_static.c +++ b/src/rmr/common/src/rtc_static.c @@ -84,6 +84,9 @@ static void* rtc_file( void* vctx ) { read_static_rt( ctx, vlevel ); // seed the route table if one provided + if( ctx->shutdown != 0 ) { // allow for graceful termination and unit testing + return NULL; + } sleep( 60 ); } } @@ -102,28 +105,103 @@ static int refresh_vlevel( int vfd ) { return vlevel; } +/* + Rtc_parse_msg parses a single message from the route manager. We allow multiple, newline terminated, + records in each message; it is required that the last record in the message be complete (we do not + reconstruct records split over multiple messages). For each record, we call the record parser + to parse and add the information to the table being built. + + This function was broken from the main rtc() function in order to be able to unit test it. Without + this as a standalone funciton, it was impossible to simulate a message arriving on the RTC's private + context. + + To reduce malloc/free cycles, we allocate a static work buffer and expand it when needed; in other + words, this is not thread safe but it shouldn't need to be. +*/ +static void rtc_parse_msg( uta_ctx_t *ctx, uta_ctx_t* pvt_cx, rmr_mbuf_t* msg, int vlevel, int* flags ) { + static unsigned char* pbuf = NULL; + static int pbuf_size = 0; + + unsigned char* payload; + unsigned char* curr; + unsigned char* nextr; + int mlen; + + payload = msg->payload; + mlen = msg->len; // usable bytes in the payload + + if( DEBUG > 1 || (vlevel > 0) ) rmr_vlog( RMR_VL_DEBUG, "rmr_rtc: received rt message type=%d len=%d\n", msg->mtype, (int) mlen ); + switch( msg->mtype ) { + case RMRRM_TABLE_DATA: + if( (*flags & RTCFL_HAVE_UPDATE) == 0 ) { + *flags |= RTCFL_HAVE_UPDATE; + rmr_vlog( RMR_VL_INFO, "message flow from route manager starts\n" ); + } + + if( pbuf_size <= mlen ) { + if( pbuf ) { + free( pbuf ); + } + if( mlen < 512 ) { + pbuf_size = 1024; + } else { + pbuf_size = mlen * 2; + } + pbuf = (char *) malloc( sizeof( char ) * pbuf_size ); + } + memcpy( pbuf, payload, mlen ); + pbuf[mlen] = 0; // don't depend on sender making this a legit string + if( vlevel > 1 ) { + rmr_vlog_force( RMR_VL_DEBUG, "rmr_rtc: rt message: (%s)\n", pbuf ); + } + + curr = pbuf; + while( curr ) { // loop over each record in the buffer + nextr = strchr( (char *) curr, '\n' ); // allow multiple newline records, find end of current and mark + + if( nextr ) { + *(nextr++) = 0; + } + + if( vlevel > 1 ) { + rmr_vlog_force( RMR_VL_DEBUG, "rmr_rtc: processing (%s)\n", curr ); + } + parse_rt_rec( ctx, pvt_cx, curr, vlevel, msg ); // parse record and add to in progress table; ack using rts to msg + + curr = nextr; + } + + msg->len = 0; // force back into the listen loop + break; + + default: + rmr_vlog( RMR_VL_WARN, "rmr_rtc: invalid message type=%d len=%d\n", msg->mtype, (int) msg->len ); + break; + } +} + /* Route Table Collector A side thread which either attempts to connect and request a table from the Route Manager, or opens a port and listens for Route Manager to push table updates. - It may do other things along the way (latency measurements, alarms, + It may do other things along the way (latency measurements, alarms, respond to RMR pings, etc.). The behaviour with respect to listening for Route Manager updates vs the initiation of the connection and sending a request depends on the value of the ENV_RTG_ADDR (RMR_RTG_SVC) environment variable. If host:port, or IP:port, is given, then we assume that we make the connection - and send a request for the table (request mode). If the variable is just - a port, then we assume Route Manager will connect and push updates (original + and send a request for the table (request mode). If the variable is just + a port, then we assume Route Manager will connect and push updates (original method). If the variable is not defined, the default behaviour, in order to be - backwards compatable, depends on the presence of the ENV_CTL_PORT + backwards compatable, depends on the presence of the ENV_CTL_PORT (RMR_CTL_PORT) variable (new with the support for requesting a table). - + ENV_CTL_PORT ENV_RTG_ADDR Behaviour unset unset Open default CTL port (DEF_CTL_PORT) and wait for Rt Mgr to push tables @@ -134,15 +212,15 @@ static int refresh_vlevel( int vfd ) { used is the value set by ENV_CTL_PORT. unset set As described above. The default control - port (DEF_CTL_PORT) is used. + port (DEF_CTL_PORT) is used. - When we are running in request mode, then we will send the RMR message - RMRRM_REFRESH to this address (wormhole) as a request for the route manager + When we are running in request mode, then we will send the RMR message + RMRRM_REFRESH to this address (wormhole) as a request for the route manager to send a new table. We will attempt to connect and send requests until we have a table. Calls to rmr_ready() will report FALSE until a table is loaded _unless_ a seed table was given. - Route table information is expected to arrive on RMR messages with type + Route table information is expected to arrive on RMR messages with type RMRRM_TABLE_DATA. There is NOT a specific message type for each possible table record, so the payload is as it appears in the seed file or as delivered in old versions. It may take several RMRRM_TABLE_DATA messages @@ -163,22 +241,16 @@ static void* rtc( void* vctx ) { uta_ctx_t* ctx; // context user has -- where we pin the route table uta_ctx_t* pvt_cx; // private context for session with rtg rmr_mbuf_t* msg = NULL; // message from rtg - char* payload; // payload in the message - size_t mlen; char* my_port; // the port number that we will listen on (4561 has been the default for this) char* rtg_addr; // host:port address of route table generator (route manager) char* daddr; // duplicated rtg address string to parse/trash size_t buf_size; // nng needs var pointer not just size? - char* nextr; // pointer at next record in the message - char* curr; // current record - int i; + int i; long blabber = 0; // time of last blabber so we don't flood if rtg goes bad int cstate = -1; // connection state to rtg int state; // processing state of some nng function char* tokens[128]; char wbuf[128]; - char* pbuf = NULL; - int pbuf_size = 0; // number allocated in pbuf int ntoks; int vfd = -1; // verbose file des if we have one int vlevel = 0; // how chatty we should be 0== no nattering allowed @@ -201,14 +273,14 @@ static void* rtc( void* vctx ) { vlevel = refresh_vlevel( vfd ); } - ctx->flags |= CFL_NO_RTACK; // don't ack when reading from a file + ctx->flags |= CFL_NO_RTACK; // don't ack when reading from a file read_static_rt( ctx, vlevel ); // seed the route table if one provided ctx->flags &= ~CFL_NO_RTACK; my_port = getenv( ENV_CTL_PORT ); // default port to listen on (likely 4561) if( my_port == NULL || ! *my_port ) { // if undefined, then go with default - my_port = DEF_CTL_PORT; + my_port = DEF_CTL_PORT; daddr = DEF_CTL_PORT; // backwards compat; if ctl port not hard defined, default is to listen } else { daddr = DEF_RTG_WK_ADDR; // if ctl port is defined, then default changes to connecting to well known RM addr @@ -235,7 +307,7 @@ static void* rtc( void* vctx ) { flags |= RTCFL_HAVE_UPDATE; // and signal not to try to request an update my_port = tokens[1]; } else { - // rtg_addr points at rt mgr address and my port set from env or default stands as is + // rtg_addr points at rt mgr address and my port set from env or default stands as is } break; } @@ -278,62 +350,16 @@ static void* rtc( void* vctx ) { rt_epcounts( ctx->rtable, ctx->my_name ); } } + + if( ctx->shutdown != 0 ) { + break; // mostly for unit test, but allows a forced stop + } } vlevel = refresh_vlevel( vfd ); // ensure it's fresh when we get a message if( msg != NULL && msg->len > 0 ) { - payload = msg->payload; - mlen = msg->len; // usable bytes in the payload - - if( DEBUG > 1 || (vlevel > 0) ) rmr_vlog( RMR_VL_DEBUG, "rmr_rtc: received rt message type=%d len=%d\n", msg->mtype, (int) mlen ); - switch( msg->mtype ) { - case RMRRM_TABLE_DATA: - if( (flags & RTCFL_HAVE_UPDATE) == 0 ) { - flags |= RTCFL_HAVE_UPDATE; - rmr_vlog( RMR_VL_INFO, "message flow from route manager starts\n" ); - } - - if( pbuf_size <= mlen ) { - if( pbuf ) { - free( pbuf ); - } - if( mlen < 512 ) { - pbuf_size = 512; - } else { - pbuf_size = mlen * 2; - } - pbuf = (char *) malloc( sizeof( char ) * pbuf_size ); - } - memcpy( pbuf, payload, mlen ); - pbuf[mlen] = 0; // don't depend on sender making this a legit string - if( vlevel > 1 ) { - rmr_vlog_force( RMR_VL_DEBUG, "rmr_rtc: rt message: (%s)\n", pbuf ); - } - - curr = pbuf; - while( curr ) { // loop over each record in the buffer - nextr = strchr( curr, '\n' ); // allow multiple newline records, find end of current and mark - - if( nextr ) { - *(nextr++) = 0; - } - - if( vlevel > 1 ) { - rmr_vlog_force( RMR_VL_DEBUG, "rmr_rtc: processing (%s)\n", curr ); - } - parse_rt_rec( ctx, pvt_cx, curr, vlevel, msg ); // parse record and add to in progress table; ack using rts to msg - - curr = nextr; - } - - msg->len = 0; // force back into the listen loop - break; - - default: - rmr_vlog( RMR_VL_WARN, "rmr_rtc: invalid message type=%d len=%d\n", msg->mtype, (int) msg->len ); - break; - } + rtc_parse_msg( ctx, pvt_cx, msg, vlevel, &flags ); } if( ctx->shutdown ) { // mostly for testing, but allows user app to close us down if rmr_*() function sets this @@ -346,7 +372,7 @@ static void* rtc( void* vctx ) { } #ifndef SI95_BUILD -// this is nng specific inas much as we allow raw (non-RMR) messages +// this is nng specific inas much as we allow raw (non-RMR) messages /* NOTE: This is the original rtc code when we supported "raw" nano/nng messages @@ -404,7 +430,7 @@ static void* raw_rtc( void* vctx ) { size_t buf_size; // nng needs var pointer not just size? char* nextr; // pointer at next record in the message char* curr; // current record - int i; + int i; long blabber = 0; // time of last blabber so we don't flood if rtg goes bad int cstate = -1; // connection state to rtg int state; // processing state of some nng function @@ -433,7 +459,7 @@ static void* raw_rtc( void* vctx ) { if( (eptr = getenv( ENV_VERBOSE_FILE )) != NULL ) { vfd = open( eptr, O_RDONLY ); vlevel = refresh_vlevel( vfd ); - } + } read_static_rt( ctx, vlevel ); // seed the route table if one provided @@ -474,7 +500,7 @@ static void* raw_rtc( void* vctx ) { sleep( count_delay ); rt_epcounts( ctx->rtable, ctx->my_name ); } - + free( fport ); // parinoid free and return return NULL; } diff --git a/src/rmr/si/src/mt_call_si_static.c b/src/rmr/si/src/mt_call_si_static.c index 2d422bb..fbbffaf 100644 --- a/src/rmr/si/src/mt_call_si_static.c +++ b/src/rmr/si/src/mt_call_si_static.c @@ -234,7 +234,7 @@ static int mt_data_cb( void* vctx, int fd, char* buf, int buflen ) { remain = 0; } else { need = river->msg_size - river->ipt; // bytes from transport we need to have complete message - if( DEBUG ) rmr_vlog( RMR_VL_DEBUG, "data callback enough in the buffer size=%d need=%d remain=%d\n", river->msg_size, need, remain ); + if( DEBUG ) rmr_vlog( RMR_VL_DEBUG, "data callback enough in the buffer size=%d need=%d remain=%d flgs=%02x\n", river->msg_size, need, remain, river->flags ); if( (river->flags & RF_DROP) == 0 ) { memcpy( &river->accum[river->ipt], buf+bidx, need ); // grab just what is needed (might be more) buf2mbuf( ctx, river->accum, river->nbytes, fd ); // build an RMR mbuf and queue @@ -242,7 +242,7 @@ static int mt_data_cb( void* vctx, int fd, char* buf, int buflen ) { river->accum = (char *) malloc( sizeof( char ) * river->nbytes ); // fresh accumulator } else { if( !(river->flags & RF_NOTIFIED) ) { - rmr_vlog( RMR_VL_WARN, "message larger than max (%d) have arrived on fd %d\n", river->nbytes, fd ); + rmr_vlog( RMR_VL_WARN, "message larger than allocated buffer (%d) arrived on fd %d\n", river->nbytes, fd ); river->flags |= RF_NOTIFIED; } } diff --git a/src/rmr/si/src/rmr_si.c b/src/rmr/si/src/rmr_si.c index d1b9f26..712275e 100644 --- a/src/rmr/si/src/rmr_si.c +++ b/src/rmr/si/src/rmr_si.c @@ -419,6 +419,10 @@ extern rmr_mbuf_t* rmr_torcv_msg( void* vctx, rmr_mbuf_t* old_msg, int ms_to ) { } /* + DEPRECATED -- this function is not needed in the SI world, and when NNG goes away this will + too. This function likely will not behave as expected in SI, and we are pretty sure it + isn't being used as there was an abort triggering reference to rmr_rcv() until now. + This blocks until the message with the 'expect' ID is received. Messages which are received before the expected message are queued onto the message ring. The function will return a nil message and set errno to ETIMEDOUT if allow2queue messages are received before the @@ -455,22 +459,25 @@ extern rmr_mbuf_t* rmr_rcv_specific( void* vctx, rmr_mbuf_t* msg, char* expect, if( DEBUG ) rmr_vlog( RMR_VL_DEBUG, " rcv_specific waiting for id=%s\n", expect ); while( queued < allow2queue ) { - msg = rcv_msg( ctx, msg ); // hard wait for next - if( msg->state == RMR_OK ) { - if( memcmp( msg->xaction, expect, exp_len ) == 0 ) { // got it -- return it - if( DEBUG ) rmr_vlog( RMR_VL_DEBUG, " rcv-specific matched (%s); %d messages were queued\n", msg->xaction, queued ); - return msg; - } - - if( ! uta_ring_insert( ctx->mring, msg ) ) { // just queue, error if ring is full - if( DEBUG > 1 ) rmr_vlog( RMR_VL_DEBUG, " rcv_specific ring is full\n" ); - errno = ENOBUFS; - return NULL; + msg = rmr_rcv_msg( ctx, msg ); // hard wait for next + if( msg != NULL ) { + if( DEBUG ) rmr_vlog( RMR_VL_DEBUG, " rcv_specific checking message; queued=%d allowed=%d state=%d\n", queued, allow2queue, msg->state ); + if( msg->state == RMR_OK ) { + if( memcmp( msg->xaction, expect, exp_len ) == 0 ) { // got it -- return it + if( DEBUG ) rmr_vlog( RMR_VL_DEBUG, " rcv_specific matched (%s); %d messages were queued\n", msg->xaction, queued ); + return msg; + } + + if( ! uta_ring_insert( ctx->mring, msg ) ) { // just queue, error if ring is full + if( DEBUG > 1 ) rmr_vlog( RMR_VL_DEBUG, " rcv_specific ring is full\n" ); + errno = ENOBUFS; + return NULL; + } + + if( DEBUG ) rmr_vlog( RMR_VL_DEBUG, " rcv_specific queued message type=%d\n", msg->mtype ); + queued++; + msg = NULL; } - - if( DEBUG ) rmr_vlog( RMR_VL_DEBUG, " rcv_specific queued message type=%d\n", msg->mtype ); - queued++; - msg = NULL; } } @@ -1079,8 +1086,10 @@ extern rmr_mbuf_t* rmr_mt_call( void* vctx, rmr_mbuf_t* mbuf, int call_id, int m // 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; + if( mbuf != NULL ) { + mbuf->state = RMR_ERR_BADARG; + mbuf->tp_state = EINVAL; + } return mbuf; } diff --git a/test/Makefile b/test/Makefile index e44b2bb..22dff3a 100644 --- a/test/Makefile +++ b/test/Makefile @@ -22,10 +22,8 @@ CC = gcc coverage_opts = -ftest-coverage -fprofile-arcs -libs = -lnng -lpthread -lm +libs = -lpthread -lm ipaths = -I ../src/rmr/common/src/ -I ../src/rmr/common/include \ - -I ../src/rmr/nng/include/ -I ../src/rmr/nng/src/ \ - -I ../src/rmr/nanomsg/include/ -I ../src/rmr/nanomsg/src/ \ -I ../src/rmr/si/include -I ../src/rmr/si/src -I ../src/rmr/si/si95 #sa_tests = sa_tools_test.o diff --git a/test/rmr_si_api_static_test.c b/test/rmr_si_api_static_test.c index 528e9cc..b7f97bf 100644 --- a/test/rmr_si_api_static_test.c +++ b/test/rmr_si_api_static_test.c @@ -96,8 +96,8 @@ static int rmr_api_test( ) { 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 + + 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 " ); } @@ -112,7 +112,7 @@ static int rmr_api_test( ) { 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 ) { @@ -210,9 +210,8 @@ static int rmr_api_test( ) { max_tries--; } - // ----- the queue load and disc cb tests should be last! ----------------------------- - for( i = 0; i < 4000; i++ ) { // test ring drop + for( i = 0; i < 4000; i++ ) { // test ring drop if( msg == NULL ) { msg = rmr_alloc_msg( rmc, 2048 ); // get a buffer with a transport header } @@ -257,6 +256,13 @@ static int rmr_api_test( ) { rmr_close( rmc ); // no return to check; drive for coverage + // --------------- nil pointer exception checks + rmr_rcv_specific( NULL, NULL, "foo", 0 ); + rmr_mt_rcv( NULL, NULL, 0 ); + mt_call( NULL, NULL, 0, 1, NULL ); + rmr_mt_call( NULL, NULL, 0, 1 ); + rmr_set_low_latency( NULL ); + rmr_set_fack( NULL ); // --------------- phew, done ------------------------------------------------------------------------------ diff --git a/test/rmr_si_rcv_static_test.c b/test/rmr_si_rcv_static_test.c index ad543a0..57313f8 100644 --- a/test/rmr_si_rcv_static_test.c +++ b/test/rmr_si_rcv_static_test.c @@ -150,6 +150,7 @@ static int rmr_rcv_test( ) { } rmr_rts_msg( NULL, NULL ); // drive for coverage + errors += fail_if( errno == 0, "rmr_rts_msg did not set errno when given a nil context " ); rmr_rts_msg( rmc, NULL ); errors += fail_if( errno == 0, "rmr_rts_msg did not set errno when given a nil message " ); @@ -225,6 +226,42 @@ static int rmr_rcv_test( ) { rmr_close( rmc ); // no return to check; drive for coverage + // ------- receive specific is deprecated, but we still test to keep sonar happy --------------- + + rmr_rcv_specific( NULL, NULL, "12345", 0 ); // drive for error handling coverage + rmr_rcv_specific( NULL, msg, "12345", 2 ); + + strncpy( wbuf, "dummy message", sizeof( wbuf ) ); + msg = mk_populated_msg( 1024, 0, 0, -1, strlen( wbuf ) + 1 ); + strncpy( msg->payload, wbuf, msg->len ); + msg = rmr_send_msg( rmc, msg ); // give specific something to chew on + + strncpy( msg->payload, wbuf, msg->len ); + msg->mtype = 0; + rmr_str2xact( msg, "12345" ); // should allow rcv to find it + msg = rmr_send_msg( rmc, msg ); + + msg = rmr_rcv_specific( rmc, NULL, "12345", 2 ); + if( msg ) { + errors += fail_if( msg->state != 0, "rmr_rcv_specific failed to find the expected message" ); + } else { + errors++; + fprintf( stderr, " rcv specific expected to return a message and did not\n" ); + } + + strncpy( wbuf, "dummy message", sizeof( wbuf ) ); + msg = mk_populated_msg( 1024, 0, 0, -1, strlen( wbuf ) + 1 ); + strncpy( msg->payload, wbuf, msg->len ); + msg = rmr_send_msg( rmc, msg ); // give specific something to chew on + + fprintf( stderr, " starting rmr_rcv_specific test for no expected message\n" ); + strncpy( msg->payload, wbuf, msg->len ); + msg->mtype = 0; + rmr_str2xact( msg, "72345" ); // rcv should not find it + msg = rmr_send_msg( rmc, msg ); + msg = rmr_rcv_specific( rmc, msg, "12345", 2 ); + fail_if_nil( msg, "rmr_rcv_specific expected to retun nil message did not" ); + // --------------- phew, done ------------------------------------------------------------------------------ if( ! errors ) { diff --git a/test/rt_static_test.c b/test/rt_static_test.c index d87a743..dbe8d78 100644 --- a/test/rt_static_test.c +++ b/test/rt_static_test.c @@ -98,6 +98,7 @@ fprintf( stderr, " build key: %x %x --> %llx\n", (int) mtype, (int) sid, ( */ static int rt_test( ) { uta_ctx_t* ctx; // context needed to test load static rt + uta_ctx_t* pctx; // "private" context for route manager communication tests route_table_t* rt; // route table route_table_t* crt; // cloned route table rtable_ent_t* rte; // route table entries from table @@ -521,6 +522,36 @@ static int rt_test( ) { errors += fail_not_equal( state, 0, "epsock_meid returned true when given nil socket pointer" ); #endif + // ------------ debugging and such; coverage only calls ---------------------------------------------------------- + ep_stats( ctx->rtable, NULL, "name", NULL, NULL ); // ensure no crash when given nil pointer + rt_epcounts( ctx->rtable, "testing" ); + rt_epcounts( NULL, "testing" ); + + buf = ensure_nlterm( strdup( "Stand up and cheer!" ) ); // force addition of newline + if( buf ) { + errors += fail_not_equal( strcmp( buf, "Stand up and cheer!\n" ), 0, "ensure nlterm didn't add newline" ); + free( buf ); + buf = NULL; + } + + + // ------------- route manager request/response funcitons ------------------------------------------------------- + { + rmr_mbuf_t* smsg; + + smsg = rmr_alloc_msg( ctx, 1024 ); + send_rt_ack( ctx, smsg, "123456", 0, "no reason" ); + + pctx = mk_dummy_ctx(); + ctx->rtg_whid = -1; + state = send_update_req( pctx, ctx ); + errors += fail_not_equal( state, 0, "send_update_req did not return 0" ); + + ctx->rtg_whid = rmr_wh_open( ctx, "localhost:19289" ); + state = send_update_req( pctx, ctx ); + errors += fail_if_equal( state, 0, "send_update_req to an open whid did not return 0" ); + } + // ------------- si only; fd to ep conversion functions --------------------------------------------------------- #ifndef NNG_UNDER_TEST diff --git a/test/si95_test.c b/test/si95_test.c index c77f389..fd6dd56 100644 --- a/test/si95_test.c +++ b/test/si95_test.c @@ -21,7 +21,7 @@ /* Mmemonic: si95_test.c Abstract: This is the main driver to test the si95 core functions - (within rmr/src/si/src/si95). + (within rmr/src/si/src/si95). Author: E. Scott Daniels Date: 6 March 2018 @@ -58,7 +58,7 @@ #define DEBUG 1 // specific test tools in this directory -#undef NNG_UNDER_TEST // NNG is NOT under test so undefine if set +#undef NNG_UNDER_TEST // NNG is NOT under test so undefine if set #define NO_EMULATION 1 // no emulation of transport functions #define NO_PRIVATE_HEADERS 1 // no rmr_si or rmr_nng headers #define NO_DUMMY_RMR 1 // no msg things @@ -127,7 +127,7 @@ static int memory( ) { ((struct tp_blk *)ptr)->squeue = iptr; SItrash( TP_BLK, ptr ); } - + ptr = SInew( GI_BLK ); errors += fail_if_nil( ptr, "memory: sinew returned nil when given giblk request" ); SItrash( GI_BLK, ptr ); // GI block cannot be trashed, ensure this (valgind will complain about a leak) @@ -155,7 +155,7 @@ static int init() { static int cleanup() { int errors = 0; - + if( ! si_ctx ) { return 0; } @@ -163,8 +163,9 @@ static int cleanup() { 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 - SIshutdown( si_ctx ); + SIconnect( si_ctx, "localhost:43086" ); // ensure context has a tp block to free on shutdown + SIshutdown( NULL ); + SIabort( si_ctx ); fprintf( stderr, " cleanup module finished with %d errors\n", errors ); @@ -194,9 +195,8 @@ static int addr() { l = SIaddress( buf1, (void **) &dest, AC_TOADDR6 ); errors += fail_if_true( l > 0, "to addr6 with bad addr convdersion returned valid len" ); - snprintf( buf1, sizeof( buf1 ), "[ff02::5]:4002" ); // v6 might not be supported so failure is OK here + snprintf( buf1, sizeof( buf1 ), "[ff02::5]:4002" ); // v6 might not be supported so failure is OK here; driving for coverage l=SIaddress( buf1, (void **) &dest, AC_TOADDR6 ); - errors += fail_if_true( l < 1, "to addr convdersion failed" ); snprintf( buf1, sizeof( buf1 ), "localhost:43086" ); l = SIaddress( buf1, (void **) &dest, AC_TOADDR ); @@ -222,11 +222,11 @@ static int conn( ) { state = SIconnect( si_ctx, "localhost:4567" ); // driver regular connect errors += fail_if_true( state < 0, "connect to low port failed" ); - state = SIconnect( si_ctx, "localhost:43086" ); // drive save connect with good return code + state = SIconnect( si_ctx, "localhost:43086" ); // drive save connect with good return code errors += fail_if_true( state < 0, "connect to high port failed" ); tpem_set_addr_dup_state( 1 ); // force get sockket name emulation to return a duplicate address - state = SIconnect( si_ctx, "localhost:43086" ); // drive save connect with good return code + state = SIconnect( si_ctx, "localhost:43086" ); // drive save connect with good return code errors += fail_if_true( state >= 0, "forced dup connect did not return error" ); tpem_set_addr_dup_state( 0 ); // force get sockket name emulation to return a duplicate address diff --git a/test/sr_si_static_test.c b/test/sr_si_static_test.c index 5768f3e..9efba71 100644 --- a/test/sr_si_static_test.c +++ b/test/sr_si_static_test.c @@ -41,7 +41,7 @@ #include "rmr_agnostic.h" // ----------- local test support ---------------------------------------------------------- -#define CLONE 1 // convenience constants for payload realloc tests +#define CLONE 1 // convenience constants for payload realloc tests #define NO_CLONE 0 #define COPY 1 #define NO_COPY 0 @@ -59,21 +59,24 @@ have been included by the test module(s) which include this. */ static int sr_si_test() { - uta_ctx_t* ctx; // context needed to test load static rt + uta_ctx_t* ctx; // two context structs needed to test route table collector + uta_ctx_t* pctx; uta_ctx_t* real_ctx; // real one to force odd situations for error testing int errors = 0; // number errors found rmr_mbuf_t* mbuf; // mbuf to send/receive rmr_mbuf_t* mb2; // second mbuf when needed int whid = -1; int last_whid; - int state; - int nn_dummy_sock; // dummy needed to drive send + int state; + int nn_dummy_sock; // dummy needed to drive send int size; int i; + int flags = 0; // flags needed to pass to rtc funcitons void* p; char* payload_str; ctx = mk_dummy_ctx(); // in the si world we need some rings in the context + pctx = mk_dummy_ctx(); ctx->max_plen = RMR_MAX_RCV_BYTES + sizeof( uta_mhdr_t ); ctx->max_mlen = ctx->max_plen + sizeof( uta_mhdr_t ); @@ -114,8 +117,7 @@ static int sr_si_test() { if( mbuf ) { errors += fail_not_equal( mbuf->state, RMR_ERR_BADARG, "send with buffer but nil context didn't return right state" ); } else { - //mbuf = rmr_rcv_msg( ctx, NULL ); -mbuf = rmr_alloc_msg( ctx, 2048 ); + mbuf = rmr_alloc_msg( ctx, 2048 ); } //size = 2048 - em_hdr_size(); // emulated receive allocates 2K buffers -- subtract off header size @@ -126,7 +128,12 @@ mbuf = rmr_alloc_msg( ctx, 2048 ); rmr_free_msg( mbuf ); - // ---- drive rtc in a 'static' (not pthreaded) mode to get some coverage; no 'results' to be verified ----- + // -------- drive rtc in a 'static' (not pthreaded) mode to get some coverage; no 'results' to be verified ----- + /* + It is impossible to drive the message loop of the rtc from a unit test because + we cannot generate a message that will arrive on its private RMR context. + */ + setenv( ENV_RTG_RAW, "0", 1 ); // rtc is never raw under SI setenv( ENV_VERBOSE_FILE, ".ut_rmr_verbose", 1 ); // allow for verbose code in rtc to be driven i = open( ".ut_rmr_verbose", O_RDWR | O_CREAT, 0654 ); @@ -136,7 +143,10 @@ mbuf = rmr_alloc_msg( ctx, 2048 ); } ctx->shutdown = 1; // should force rtc to quit on first pass rtc( NULL ); // coverage test with nil pointer -/* + + rtc_file( NULL ); // the static file only collector + rtc_file( ctx ); + rtc( ctx ); setenv( "RMR_RTG_SVC", "4567", 1 ); // drive for edge case coverage to ensure no nil pointer etc @@ -145,7 +155,17 @@ mbuf = rmr_alloc_msg( ctx, 2048 ); rtc( ctx ); setenv( "RMR_RTG_SVC", "tcp:4567:error", 1 ); rtc( ctx ); -*/ + setenv( "RMR_RTG_SVC", "localhost:4589", 1 ); // should force a request to be sent though no reponse back. + rtc( ctx ); + + payload_str = "newrt|start|abc-def\nmse|10|-1|host1:43086\nmse|20|-1|host1:43086\nnewrt|end|2\n"; + mbuf = mk_populated_msg( 1024, 0, 20, -2, strlen( payload_str ) ); + memcpy( mbuf->payload, payload_str, mbuf->len ); + rtc_parse_msg( ctx, pctx, mbuf, 5, &flags ); + + mbuf = mk_populated_msg( 1024, 0, 90, -2, strlen( payload_str ) ); // drive with invalid message type for coverage + rtc_parse_msg( ctx, pctx, mbuf, 5, &flags ); + // ------------- reallocation tests ------------------------------------------------------------ // we use mk_populated_msg() to create a message with mid/sid/plen pushed into the transport diff --git a/test/test_ctx_support.c b/test/test_ctx_support.c index 277f741..2a66c04 100644 --- a/test/test_ctx_support.c +++ b/test/test_ctx_support.c @@ -63,10 +63,12 @@ static inline uta_ctx_t *mk_dummy_ctx() { } memset( ctx, 0, sizeof( *ctx ) ); - + ctx->mring = uta_mk_ring( 4096 ); // message ring is always on for si ctx->zcb_mring = uta_mk_ring( 128 ); // zero copy buffer mbuf ring to reduce malloc/free calls ctx->si_ctx = malloc( 1024 ); + ctx->my_name = strdup( "hostname1" ); + ctx->my_ip = strdup( "123.45.67.89" ); return ctx; } diff --git a/test/unit_test.ksh b/test/unit_test.ksh index ad21465..718055a 100755 --- a/test/unit_test.ksh +++ b/test/unit_test.ksh @@ -190,7 +190,7 @@ function discount_an_checks { } } - /-:/ { # skip unexecutable lines + /-:/ { # skip unexecutable lines spit_line() seq++ # allow blank lines in a sequence group next @@ -345,7 +345,8 @@ show_output=0 # show output from each test execution (-S) quiet=0 gen_xml=0 replace_flags=1 # replace ##### in gcov for discounted lines -run_nano_tests=0 +run_nano_tests=0 # can nolonger be turned on +run_nng_tests=0 # -N will enable always_gcov=0 # -a sets to always run gcov even if failure save_gcov=1 # -o turns this off out_dir=${UT_COVERAGE_DIR:-/tmp/rmr_gcov} # -O changes output directory @@ -360,7 +361,7 @@ do -C) builder="$2"; shift;; # custom build command -G) builder="gmake %s";; -M) builder="mk -a %s";; # use plan-9 mk (better, but sadly not widly used) - -N) run_nano_tests=1;; + -N) run_nng_tests=1;; -O) out_dir=$2; shift;; -a) always_gcov=1;; @@ -385,9 +386,9 @@ do ;; - -h) usage; exit 0;; + -h) usage; exit 0;; --help) usage; exit 0;; - -\?) usage; exit 0;; + -\?) usage; exit 0;; *) echo "unrecognised option: $1" >&2 usage >&2 @@ -399,7 +400,7 @@ do done -if (( strict )) # if in strict mode, coverage shortcomings are failures +if (( strict )) # if in strict mode, coverage shortcomings are failures then cfail="FAIL" else @@ -418,11 +419,16 @@ then do if [[ $tfile != *"static_test.c" ]] then - if(( ! run_nano_tests )) && [[ $tfile == *"nano"* ]] + if (( ! run_nng_tests )) && [[ $tfile == *"nng"* ]] # drop any nng file unless -N given + then + continue + fi + if [[ $tfile == *"nano"* ]] # no longer support nano tests; drop regardless then continue fi + echo " add test: $tfile" >&2 flist="${flist}$tfile " fi done @@ -445,6 +451,11 @@ rm -fr *.gcov # ditch the previous coverage files ut_errors=0 # unit test errors (not coverage errors) errors=0 +if ! touch /tmp/PPID$$.noise +then + echo " unable to write to /tmp???" +fi + for tfile in $flist do for x in *.gcov @@ -455,14 +466,14 @@ do fi done + echo "$tfile --------------------------------------" ( # all noise is now captured into a tmp file to support quiet mode - echo "$tfile --------------------------------------" bcmd=$( printf "$builder" "${tfile%.c}" ) if ! $bcmd >/tmp/PID$$.log 2>&1 then echo "[FAIL] cannot build $tfile" cat /tmp/PID$$.log - rm -f /tmp/PID$$ + # do NOT remove tmp files; bash seens to not gen a new PID for subshells exit 1 fi @@ -612,7 +623,6 @@ do } } } - } END { @@ -623,7 +633,7 @@ do rc=$? cat /tmp/PID$$.log - if (( rc || force_discounting )) # didn't pass, or forcing, see if discounting helps + if (( rc || force_discounting )) # didn't pass, or forcing, see if discounting helps then if (( ! verbose )) then @@ -645,7 +655,7 @@ do tail -1 /tmp/PID$$.disc | grep '\[' - if (( verbose > 1 )) # updated file was generated, keep here + if (( verbose > 1 )) # updated file was generated, keep here then echo "[INFO] discounted coverage info in: ${tfile##*/}.dcov" fi @@ -653,7 +663,7 @@ do mv /tmp/PID$$.disc ${name##*/}.dcov done fi - )>/tmp/PID$$.noise 2>&1 + )>/tmp/PID$$.noise 2>&1 if (( $? != 0 )) then (( ut_errors++ )) @@ -685,7 +695,7 @@ do if [[ $xx != *"test"* ]] then of=${xx%.gcov}.dcov - discount_an_checks $xx >$of + discount_an_checks $xx >$of if [[ -n $of ]] then tail -1 $of | grep '\[' -- 2.16.6