Add first set of SI95 unit tests and health check 21/2621/12 3.3.0
authorE. Scott Daniels <daniels@research.att.com>
Fri, 21 Feb 2020 18:24:29 +0000 (13:24 -0500)
committerScott Daniels <daniels@research.att.com>
Wed, 4 Mar 2020 14:15:23 +0000 (14:15 +0000)
This change adds the first series of unit tests for
the RMR SI95 code.  It also bundles the running of
the unit tests and the application level tests into
the CMake description such that "make test" will
run them all.

The health check application (health_ck) is now built
from the "support" source and added to the RMR run-time
package in /usr/local/bin.

Issue-ID: RIC-151

Signed-off-by: E. Scott Daniels <daniels@research.att.com>
Change-Id: I72804452afa5a972aa4ca0ded7b68131e16f5955

41 files changed:
CHANGES
CMakeLists.txt
ci/build_all.sh [new file with mode: 0755]
src/rmr/common/src/symtab.c
src/rmr/si/src/mt_call_si_static.c
src/rmr/si/src/rtable_si_static.c
src/rmr/si/src/sr_si_static.c
src/support/CMakeLists.txt [new file with mode: 0644]
src/support/README [new file with mode: 0644]
src/support/health_ck.c [new file with mode: 0644]
test/Makefile
test/app_test/Makefile
test/app_test/run_all.ksh
test/app_test/run_app_test.ksh
test/app_test/run_call_test.ksh
test/app_test/run_exrts_test.ksh
test/app_test/run_lcall_test.ksh
test/app_test/run_multi_test.ksh
test/app_test/run_rr_test.ksh
test/app_test/run_rts_test.ksh
test/hdr_static_test.c
test/logging_test.c
test/mbuf_api_test.c
test/ring_test.c
test/rmr_nng_test.c
test/rmr_si_api_static_test.c [new file with mode: 0644]
test/rmr_si_test.c [new file with mode: 0644]
test/rt_static_test.c
test/run_app_tests [new file with mode: 0644]
test/sr_si_static_test.c [new file with mode: 0644]
test/symtab_static_test.c
test/symtab_test.c
test/test_common_em.c [new file with mode: 0644]
test/test_ctx_support.c [new file with mode: 0644]
test/test_nng_em.c
test/test_si95_em.c [new file with mode: 0644]
test/test_support.c
test/tools_static_test.c
test/tools_test.c
test/unit_test.ksh
test/wormhole_static_test.c

diff --git a/CHANGES b/CHANGES
index eb98292..cb8c214 100644 (file)
--- a/CHANGES
+++ b/CHANGES
@@ -2,6 +2,10 @@
 API and build change  and fix summaries. Doc correctsions
 and/or changes are not mentioned here; see the commit messages.
 
+2020 February 29; Version 2.4.0
+       Add consolidated testing under CMake
+       Add support binary for health check (SI95 only)
+
 2020 February 28; Version 2.3.6
        Fix bug in Rt. Mgr comm which prevented table ID from being
        sent on ack message (RIC-232).
index c0dc0ef..55719b9 100644 (file)
 #      -DSKIP_EXTERNALS=1      Do not use NNG submodule when building; uee installed packages
 #      -DMAN_PREFIX=<path>     Supply a path where man pages are installed (default: /usr/share/man)
 
+#      See ci/build_all for an example of how to build and test
+
 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 "2" )
-set( patch_level "6" )
+set( minor_version "3" )
+set( patch_level "0" )
 
 set( install_root "${CMAKE_INSTALL_PREFIX}" )
 set( install_inc "include/rmr" )
@@ -293,6 +295,28 @@ if( need_ext )
        endif()
 endif()
 
+# ------------- testing -------------------------------------------------------
+enable_testing()
+add_test(
+               NAME drive_unit_tests
+               COMMAND bash ../test/unit_test.ksh -q 
+               WORKING_DIRECTORY ../test
+)
+
+# cmake seems unable to start test/app_test/run_all.ksh, so we have to lump
+# a dummy script in ./test that does the obvious thing.
+add_test(
+               NAME drive_app
+               COMMAND bash  ./run_app_tests LD_LIBRARY_PATH=${install_root}/lib C_INCLUDE_PATH=${install_root}/include
+               WORKING_DIRECTORY ../test
+)
+
+
+# --- support binaries that depend on the libs identified above ---------------
+add_subdirectory( src/support )
+
+# ------------- packaging -----------------------------------------------------
+
 #
 if( APPLE  )
        message( "### apple hack: forcing hard coded library paths for nng/nano dynamic libraries" )
diff --git a/ci/build_all.sh b/ci/build_all.sh
new file mode 100755 (executable)
index 0000000..30d7330
--- /dev/null
@@ -0,0 +1,58 @@
+#!/usr/bin/env bash
+# :vim ts=4 sw=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.
+#==================================================================================
+#
+
+#      Mnemonic:       build_all.sh
+#      Abstract:       To setup CMake and build multiple packages with varying content
+#                              (dev and runtime) it may be easier to run a single script.
+#                              This is that script which will:
+#                                      1) make the .build directory
+#                                      2) run cmake to configure the dev package
+#                                      3) build the dev package
+#                                      4) run cmake to conigure the runtime package
+#                                      5) build the runtime package
+#                                      6) run unit tests
+#
+#                              Assumptions:
+#                                      We assume that this scirpt is executed at the 'root' of the
+#                                      RMr repo (i.e. the directory which has a subdirectory ci).
+#                                      e.g.  bash ci/build_all.sh
+#
+#                              Coverage Files
+#                              As a part of unit testing, coverage files are left in /tmp/rmr_gcov
+#                              which can be overridden by setting the environment variable
+#                              UT_COVERAGE_DIR.
+#
+#      Returns:        The exit code will be non-zero on failure, and 0 if all builds and
+#                              the tests pass.
+#
+#      Date:           28 February 2010
+# --------------------------------------------------------------------------------
+
+set -e         # lazy error checking
+mkdir -p .build
+cd .build
+cmake .. -DDEV_PKG=1 -DBUILD_DOC=1
+make package install
+cmake .. -DDEV_PKG=0
+make package install
+make test ARGS="-V"
+
+exit $?
+
index 8b94a41..a105187 100644 (file)
@@ -470,11 +470,13 @@ extern void rmr_sym_foreach_class( void *vst, unsigned int class, void (* user_f
 
        if( st && (list = st->symlist) != NULL && user_fun != NULL )
                for( i = 0; i < st->size; i++ )
-                       for( se = list[i]; se; se = next )              /* using next allows user to delet via this */
+                       for( se = list[i]; se; se = next )              /* using next allows user to delete via this */
                        {
-                               next = se->next;
-                               if( class == se->class ) {
-                                       user_fun( st, se, se->name, se->val, user_data );
+                               if( se ) {
+                                       next = se->next;
+                                       if( class == se->class ) {
+                                               user_fun( st, se, se->name, se->val, user_data );
+                                       }
                                }
                        }
 }
index 2894cdb..d18a8e0 100644 (file)
@@ -166,10 +166,13 @@ static int mt_data_cb( void* vctx, int fd, char* buf, int buflen ) {
                                bidx += need;
                                remain -= need;
                                river->msg_size = *((int *) river->accum);              
-                               if( DEBUG > 1 ) {
+                               if( DEBUG ) {
                                        rmr_vlog( RMR_VL_DEBUG, "size from accumulator =%d\n", river->msg_size );
-                                       if( river->msg_size > 500 ) {
-                                               dump_40( river->accum, "msg size way too large accum:"  );
+                                       if( DEBUG > 1 ) {
+                                               dump_40( river->accum, "from accumulator:"  );
+                                               if( river->msg_size > 100 ) {
+                                                       dump_40( river->accum + 50, "from rmr buf:"  );
+                                               }
                                        }
                                }
                        } else {
index 0f796e3..86f50fe 100644 (file)
@@ -225,6 +225,7 @@ static int uta_epsock_byname( uta_ctx_t* ctx, char* ep_name, int* nn_sock, endpo
 
        if( PARINOID_CHECKS ) {
                if( ctx == NULL || (rt = ctx->rtable) == NULL || (si_ctx = ctx->si_ctx) == NULL  ) {
+                       if( DEBUG ) rmr_vlog( RMR_VL_DEBUG, "epsock_byname: parinoia check pop ctx=%p rt=%p\n", ctx, rt );
                        return FALSE;
                }
        } else {
@@ -233,6 +234,7 @@ static int uta_epsock_byname( uta_ctx_t* ctx, char* ep_name, int* nn_sock, endpo
        }
 
        ep =  rmr_sym_get( rt->hash, ep_name, 1 );
+       if( DEBUG ) rmr_vlog( RMR_VL_DEBUG, "epsock_byname: ep not found: %s\n", ep_name );
        if( uepp != NULL ) {                                                    // caller needs endpoint too, give it back
                *uepp = ep;
        }
index 485611e..8f2c6f1 100644 (file)
@@ -143,7 +143,7 @@ static rmr_mbuf_t* alloc_zcmsg( uta_ctx_t* ctx, rmr_mbuf_t* msg, int size, int s
 
 /*
        memset( msg->tp_buf, 0, mlen );    // NOT for production (debug only)   valgrind will complain about uninitalised use if we don't set
-       memcpy( msg->tp_buf, "@@!!@@!!@@!!@@!!@@!!@@!!@@!!@@!!**", TPHDR_LEN );         // NOT for production -- debugging eyecatcher
+       memcpy( msg->tp_buf, "@@!!@@!!@@!!@@!!@@!!@@!!@@!!@@!!**", TP_HDR_LEN );                // NOT for production -- debugging eyecatcher
 */
        alen = (int *) msg->tp_buf;
        *alen = mlen;                                           // FIX ME: need a stuct to go in these first bytes, not just dummy len
diff --git a/src/support/CMakeLists.txt b/src/support/CMakeLists.txt
new file mode 100644 (file)
index 0000000..0147234
--- /dev/null
@@ -0,0 +1,34 @@
+#
+#==================================================================================
+#      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.
+#==================================================================================
+#
+
+# build support tools and setup for their install
+add_executable( health_ck health_ck.c )
+target_link_libraries( health_ck rmr_si_shared;pthread;m )
+
+include_directories( ${CMAKE_SOURCE_DIR}/src/rmr/common/include )
+
+
+# install only into the runtime package
+if( NOT DEV_PKG )
+       install(
+       TARGETS health_ck
+       DESTINATION ${install_root}/bin
+       )
+endif()
+
diff --git a/src/support/README b/src/support/README
new file mode 100644 (file)
index 0000000..7e274d1
--- /dev/null
@@ -0,0 +1,34 @@
+#
+#==================================================================================
+#       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.
+#==================================================================================
+#
+
+This directory contains the source for any support tools which
+are distributed with the RMR runtime package.  Support tools
+might provide means to query information about an RMR based
+application using the RMR_CTL_PORT.
+
+Support tools:
+       health_ck       -- A generic health check application which
+                               sends n messages to the application running
+                               at the indicated host:port and expects to
+                               receive n responses. Exit code is a simple
+                               binary: 0 == received responses, 1 == failure.
+
+
+Support tools are automatically built and included in the 
+runtime package (deb or rpm).
diff --git a/src/support/health_ck.c b/src/support/health_ck.c
new file mode 100644 (file)
index 0000000..b755077
--- /dev/null
@@ -0,0 +1,281 @@
+// :vim ts=4 sw=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.
+==================================================================================
+*/
+
+/*
+       Mnemonic:       health_ck.c
+       Abstract:       This is a generic, and very simplistic, health check application
+                               which will send n RMR messages to an application (localhost:4560
+                               by default) and expect to receive n responses.  Messages are sent
+                               with the message type RIC_HEALTH_CHECK_REQ and responses are 
+                               expected to have a message type RIC_HEALTH_CHECK_RESP (defined in
+                               the RIC message type header file).
+
+                               Responses are expected to have a payload containing ASCII data.
+                               The first, space separated token, is expected to be one of:
+                                       OK
+                                       ERR
+
+                               to indicate the state of the response. The ERR token may optionally
+                               be followed with a text string; when present it will be written on
+                               standard error as an aide to problem determination if needed. 
+
+                               The programme exit code will be 0 on success (all received messages
+                               had the OK token), or 1 to indicate failure. A failure reason will
+                               also be written to standard error.
+
+                               Command line options and parameters:
+                                       [-h host:port]          target application to "ping"
+                                       [-n num-msgs]           total number of "pings" to send
+                                       [-p port]                       specific port to open and use for responses
+                                       [-t seconds]            max timeout (default 3 seconds)
+
+                               Route table:  While we don't need a route table to do wormhole sends we
+                               do need for RMR to initialise an empty one. To avoid having to have a
+                               dummy table on disk somewhere, we'll create one and "point" RMR at it.
+
+       Date:           26 February 2020
+       Author:         E. Scott Daniels
+*/
+
+#include <unistd.h>
+#include <errno.h>
+#include <string.h>
+#include <stdio.h>
+#include <stdlib.h>
+#include <sys/epoll.h>
+#include <time.h>
+#include <fcntl.h>
+
+/*
+   CAUTION:
+               This is built as a part of the RMR project by CMake, not as a standalone binary.
+               As such the includes do NOT have the leading 'rmr/' as a normal application
+               might have.  (there is no such thing as /usr/local/include/rmr while building
+               the project!)
+*/
+#include <rmr.h>
+#include <RIC_message_types.h>
+
+#ifndef RIC_HEALTH_CHECK_REQ
+#define RIC_HEALTH_CHECK_REQ   100
+#define RIC_HEALTH_CHECK_RESP  101
+#endif
+
+
+#define MAX_MSG_SZ     2048            // max size we'll expect back
+#define PAYLOAD_SZ     1024            // size of payload we will send
+
+#define VERBOSE(...) if(verbose){ fprintf( stderr,  "[INFO] " __VA_ARGS__);}
+
+/*
+       we can compute the latency.
+typedef struct trace_data {
+       char    id[10];                                 // allows us to verify that it's valid
+       struct  timespec out_ts;                // time this payload was sent
+} trace_data_t;
+*/
+
+// ---------------------------------------------------------------------------
+
+/*
+       Compute the elapsed time between ts1 and ts2.
+       Returns mu-seconds.
+*/
+static int elapsed( struct timespec* start_ts, struct timespec* end_ts ) {
+       long long start;
+       long long end;
+       int bin;
+
+       start = ( start_ts->tv_sec * 1000000000) + start_ts->tv_nsec;
+       end = ( end_ts->tv_sec * 1000000000) + end_ts->tv_nsec;
+
+       bin = (end - start) / 1000;                     // to mu-sec
+       //bin = (end - start);
+
+       return bin;
+}
+
+int main( int argc, char** argv ) {
+       int             ai = 1;                                                 // arg index
+       int             i;
+
+       void* mrc;                                                      // msg router context
+       rmr_mbuf_t*             mbuf;                                   // message buffer
+       char*   payload;                                                // direct reference to msg payload
+       long    expiry;                                                 // point at which we give up (expire)
+       long    now;                                                    // current time
+       long    max_timeout = 3;                                // (seconds) -t to overrride
+       char*   target = "localhost:4560";              // address of target to ping
+       char*   listen_port = NULL;                             // the port we open for "backhaul" connections (somewhat random by default)
+       int             rand_port = 1;                                  // -r turns off and we use a default port value
+       char*   tok;                                                    // pointer at token in a buffer
+       char    wbuf[MAX_MSG_SZ];                               // work buffer
+       char*   rbuf;                                                   // spot to work on the response
+       int             whid;                                                   // id of wormhole
+       int             num2send = 1;                                   // number of messages to send
+       int             count = 0;
+       int             good = 0;                                               // num good messages back
+       int             verbose = 0;
+       int             et;                                                             // elapsed time
+       struct  timespec out_ts;                                // time we sent the message
+       struct  timespec in_ts;                                 // time we got response
+
+       // ---- simple arg parsing ------
+       while( ai < argc ) {
+               if( *argv[ai] == '-' ) {
+                       switch( argv[ai][1] ) {
+                               case 'h':                                       // host:port
+                                       ai++;
+                                       target = strdup( argv[ai] );
+                                       break;
+
+                               case 'n':                                       // num to send
+                                       ai++;
+                                       num2send = atoi( argv[ai] );
+                                       break;
+
+                               case 'p':                                       // num to send
+                                       ai++;
+                                       listen_port = strdup( argv[ai] );
+                                       break;
+
+                               case 'r':                                       // generate random listen port
+                                       rand_port = 0;
+                                       ;;
+
+                               case 't':                                       // timeout
+                                       ai++;
+                                       max_timeout = atoi( argv[ai] );
+                                       break;
+
+                               case 'v':
+                                       verbose = 1;
+                                       break;
+
+                               default:
+                                       fprintf( stderr, "[FAIL] unrecognised option: %s\n", argv[ai] );
+                                       exit( 1 );
+                       }
+
+                       ai++;
+               } else {
+                       break;          // not an option, leave with a1 @ first positional parm
+               }
+       }
+
+       
+       if( listen_port == NULL ) {
+               if( rand_port ) {                               // generate a somewhat random listen port (RMR needs)
+                       srand( time( NULL ) );
+                       snprintf( wbuf, sizeof( wbuf ), "%d", 43000 + (rand() % 1000) );
+                       listen_port = strdup( wbuf );
+               } else {
+                       listen_port = "43086";          // -r given to disable random; go with static value
+               }
+       }
+
+
+       VERBOSE( "listen port: %s; sending %d messages\n", listen_port, num2send );
+
+       if( (mrc = rmr_init( listen_port, MAX_MSG_SZ, RMRFL_NOTHREAD )) == NULL ) {             // start without route table listener thread
+               fprintf( stderr, "[FAIL] unable to initialise RMR\n" );
+               exit( 1 );
+       }
+       while( ! rmr_ready( mrc ) ) {
+               VERBOSE( "waiting for RMR to show ready\n" );
+               sleep( 1 );
+       }
+       VERBOSE( "RMR initialised\n" );
+
+       mbuf = rmr_alloc_msg( mrc, MAX_MSG_SZ );                // enough room for us, and provide app with extra room for response
+
+       VERBOSE( "starting session with %s, starting to send\n", target );
+       whid = rmr_wh_open( mrc, target );                                                              // open a wormhole directly to the target
+       if( whid < 0 ) {
+               fprintf( stderr, "[FAIL] unable to connect to %s\n", target );
+               exit( 1 );
+       }
+
+       VERBOSE( "connected to %s, sending %d pings\n", target, num2send );
+
+       now = time( NULL );
+       expiry =  now + max_timeout;                                            // when we can end this madness
+
+       while( count < num2send && now < expiry ) {                     // until we've sent and recevied n things, or we expire
+               if( !mbuf ) {
+                       fprintf( stderr, "[FAIL] internal mishap: mbuf is nil?\n" );
+                       exit( 1 );
+               }
+
+               payload = mbuf->payload;
+               snprintf( payload, PAYLOAD_SZ-1, "health check request prev=%d <eom>", count );
+
+               mbuf->mtype = RIC_HEALTH_CHECK_REQ;
+               mbuf->sub_id = -1;
+               mbuf->len =  PAYLOAD_SZ;                // yes; we're sending more than we filled so xapp has good size for response data if needed
+               mbuf->state = 0;
+
+               VERBOSE( "sending message: %s\n", payload );
+               clock_gettime( CLOCK_MONOTONIC, &out_ts );              // mark time out
+               mbuf = rmr_wh_send_msg( mrc, whid, mbuf );
+
+               if( mbuf->state == RMR_OK ) {                                                   // good send, wait for response
+                       do {
+                               mbuf = rmr_torcv_msg( mrc, mbuf, 250 );                                 // wait for a response, but break often to check for timeout
+                               clock_gettime( CLOCK_MONOTONIC, &in_ts );                               // mark time in (assuming there is a message)
+                               now = time( NULL );
+                       } while( mbuf->state == RMR_ERR_TIMEOUT && now < expiry );
+
+                       if( mbuf->state == RMR_OK ) {
+                               if( mbuf->mtype == RIC_HEALTH_CHECK_RESP ) {
+                                       payload = mbuf->payload;
+                                       memset( wbuf, 0, sizeof( wbuf ) );
+                                       memcpy( wbuf, payload, mbuf->len > sizeof( wbuf ) ? sizeof(wbuf)-1 : mbuf->len );
+                                       VERBOSE( "got: (%s) state=%d\n", wbuf, mbuf->state );
+
+                                       if( strncmp( payload, "OK", 2 ) == 0 ) {
+                                               good++;
+                                               et = elapsed( &out_ts, &in_ts );
+                                               VERBOSE( "good response received; elapsed time = %d mu-sec\n", et );
+                                       } else {
+                                               fprintf( stderr, "[WARN] xAPP response: %s\n", wbuf );
+                                       }
+                               } else {
+                                       fprintf( stderr, "[WARN] invalid message type received: %d\n", mbuf->mtype );
+                               }
+
+                               count++;
+                       } else {
+                               fprintf( stderr, "[FAIL] too few messages recevied during timeout window: wanted %d got %d\n", num2send, count );
+                               break;
+                       }
+               } else {
+                       fprintf( stderr, "[FAIL] send failed: %d %d %s\n", mbuf->state, errno, strerror( errno ) );
+                       break;
+               }
+
+               now = time( NULL );
+       }
+
+       rmr_wh_close( mrc, whid );
+
+       return good == 0;                       // if none were good, then exit 1
+}
+
index 40d9fc1..e44b2bb 100644 (file)
 CC = gcc
 coverage_opts = -ftest-coverage -fprofile-arcs
 
-libs =   -lnng -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/ 
+libs = -lnng -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
 
@@ -33,9 +36,9 @@ ipaths = -I ../src/rmr/common/src/ -I ../src/rmr/common/include -I ../src/rmr/nn
 %:: %.c
        $(CC)  $(ipaths) $(coverage_opts) -fPIC -g $< -o $@  $(libs)
 
-# catch all
+# run all tests; generates .gcov and .dcov files.
 all:
-       echo "run unit_test.ksh to make and run things here"
+       unit_test.ksh
 
 
 # remove intermediates
index fe4cd33..8fd68f0 100644 (file)
@@ -38,8 +38,9 @@ ex_cflags = $(shell echo $$EX_CFLAGS )
 build_path ?= ../../.build
 header_path := $(shell find $(build_path) -name 'rmr.h' |head -1 | sed 's!/rmr/.*!!' )
 
-C_INCLUDE_PATH := $(header_path)
-LD_LIBRARY_PATH=$(build_path):$(build_path)/lib
+# use from environment if there so as to allow build to reference installed base
+C_INCLUDE_PATH ?= $(header_path)
+LD_LIBRARY_PATH ?= $(build_path):$(build_path)/lib
 LIBRARY_PATH = $(LD_LIBRARY_PATH)
 
 # These programmes are designed to test some basic application level functions
@@ -47,7 +48,7 @@ LIBRARY_PATH = $(LD_LIBRARY_PATH)
 
 
 .PHONY: all all_si
-all: sender receiver caller mt_receiver v_sender ex_rts_receiver
+all: sender receiver caller mt_receiver v_sender ex_rts_receiver sender_si receiver_si
 
 all_si: sender_si receiver_si
 
index 1aebe03..8cc578c 100644 (file)
 function run_test {
        if [[ -n $capture_file ]]
        then
-               if ! ksh $@ >>$capture_file 2>&1
+               if ! $shell $@ >>$capture_file 2>&1
                then
                        echo "[FAIL] test failed; see $capture_file"
                        (( errors++ ))
                fi
        else
-               if ! ksh $@
+               if ! $shell $@
                then
                        (( errors++ ))
                fi
@@ -40,6 +40,23 @@ build=""
 errors=0
 si_flag=""                             # eventually we'll default to -S to run SI tests over NNG tests
 
+src_root="../.."
+if [[ -d $src_root/.build ]]                   # look for build directory in expected places
+then                                                                   # run scripts will honour this
+       export BUILD_PATH=$src_root/.build
+else
+       if [[ -d $src_root/build ]]
+       then
+               export BUILD_PATH=$src_root/build
+       fi
+fi
+
+if whence ksh >/dev/null 2>&1
+then
+       shell=ksh
+else
+       shell=bash
+fi
 while [[ $1 == "-"* ]]
 do
        case $1 in
@@ -48,6 +65,7 @@ do
                -i)     installed="-i";;
                -N)     si_flag="";;                    # turn on NNG tests (off si)
                -S)     si_flag="-S";;                  # turn on si based tests
+               -s) shell=$2; shift;;
 
                *)      echo "'$1' is not a recognised option and is ignored";;
        esac
@@ -55,8 +73,13 @@ do
        shift
 done
 
+export SHELL=$shell
+
 echo "----- app --------------------"
-run_test run_app_test.ksh $si_flag -v $installed $build
+if which ip >/dev/null 2>&1
+then
+       run_test run_app_test.ksh $si_flag -v $installed $build
+fi
 
 echo "----- multi ------------------"
 run_test run_multi_test.ksh $si_flag
index 65adf68..ef12a00 100644 (file)
@@ -168,7 +168,7 @@ else
        if (( rebuild ))
        then
                set -e
-               ksh ./rebuild.ksh $nopull | read build_path
+               $SHELL ./rebuild.ksh $nopull | read build_path
                set +e
        else
                build_path=${BUILD_PATH:-"../../.build"}        # we prefer .build at the root level, but allow user option
@@ -194,9 +194,11 @@ export RMR_SEED_RT=${RMR_SEED_RT:-./app_test.rt}           # allow easy testing with diff
 
 if (( force_make )) || [[ ! -f ./sender${si} || ! -f ./receiver${si} ]]
 then
-       if ! make -B sender${si} receiver${si} >/dev/null 2>&1
+       if ! make -B sender${si} receiver${si} >/tmp/PID$$.clog 2>&1
        then
                echo "[FAIL] cannot find sender${si} and/or receiver${si}binary, and cannot make them.... humm?"
+               head -50 /tmp/PID$$.clog
+               rm -fr /tmp/PID$$.*
                exit 1
        fi
 fi
index 207bb40..1028523 100644 (file)
@@ -157,7 +157,7 @@ if (( rebuild ))
 then
        build_path=../../.build
        set -e
-       ksh ./rebuild.ksh
+       $SHELL ./rebuild.ksh
        set +e
 else
        build_path=${BUILD_PATH:-"../../.build"}        # we prefer .build at the root level, but allow user option
@@ -174,12 +174,13 @@ if (( dev_base ))                                                 # assume we are testing against what we've built, not wh
 then
        if [[ -d $build_path/lib64 ]]
        then
-               export LD_LIBRARY_PATH=$build_path:$build_path/lib64
+               export LD_LIBRARY_PATH=$build_path:$build_path/lib64:$LD_LIBRARY_PATH
        else
-               export LD_LIBRARY_PATH=$build_path:$build_path/lib
+               export LD_LIBRARY_PATH=$build_path:$build_path/lib:$LD_LIBRARY_PATH
        fi
+       export LIBRARY_PATH=$LD_LIBRARY_PATH
 else                                                                           # -D option gets us here to test an installed library
-       export LD_LIBRARY_PATH=/usr/local/lib
+       export LD_LIBRARY_PATH=/usr/local/lib:$LD_LIBRARY_PATH
        export LIBRARY_PATH=$LD_LIBRARY_PATH
 fi
 
index 58913b4..9bd198d 100644 (file)
@@ -150,14 +150,13 @@ fi
 
 if (( use_installed ))                 # point at installed library
 then
-       export LD_LIBRARY_PATH=/usr/local/lib
-       export LIBRARY_PATH=$LD_LIBRARY_PATH
+       export LD_LIBRARY_PATH=${LD_LIBRARY_PATH-:/usr/local/lib}       # use caller's or set sane default
 else
        if (( rebuild ))
        then
                build_path=../../.build         # if we rebuild we can insist that it is in .build :)
                set -e
-               ksh ./rebuild.ksh
+               $SHELL ./rebuild.ksh
                set +e
        else
                build_path=${BUILD_PATH:-"../../.build"}        # we prefer .build at the root level, but allow user option
@@ -172,9 +171,9 @@ else
 
        if [[ -d $build_path/lib64 ]]
        then
-               export LD_LIBRARY_PATH=$build_path:$build_path/lib64
+               export LD_LIBRARY_PATH=$build_path:$build_path/lib64:$LD_LIBRARY_PATH
        else
-               export LD_LIBRARY_PATH=$build_path:$build_path/lib
+               export LD_LIBRARY_PATH=$build_path:$build_path/lib:$LD_LIBRARY_PATH
        fi
 fi
 
@@ -183,9 +182,12 @@ export RMR_SEED_RT=./ex_rts.rt
 
 set_rt $nrcvrs                                                                                                         # set up the rt for n receivers
 
-if ! make -B $mt_call_flag v_sender${si} ex_rts_receiver${si} >/tmp/PID$$.log 2>&1                     # for sanity, always rebuild test binaries
+if ! build_path=$build_path make -B $mt_call_flag v_sender${si} ex_rts_receiver${si} >/tmp/PID$$.log 2>&1                      # for sanity, always rebuild test binaries
 then
        echo "[FAIL] cannot make binaries"
+       echo "====="
+       env
+       echo "====="
        cat /tmp/PID$$.log
        rm -f /tmp/PID$$*
        exit 1
index 2a34d93..241deb5 100644 (file)
@@ -149,14 +149,13 @@ fi
 
 if (( use_installed ))                 # point at installed library
 then
-       export LD_LIBRARY_PATH=/usr/local/lib
-       export LIBRARY_PATH=$LD_LIBRARY_PATH
+       export LD_LIBRARY_PATH=${LD_LIBRARY_PATH-:/usr/local/lib}       # use caller's or set sane default
 else
        if (( rebuild ))
        then
                build_path=../../.build         # if we rebuild we can insist that it is in .build :)
                set -e
-               ksh ./rebuild.ksh
+               $SHELL ./rebuild.ksh
                set +e
        else
                build_path=${BUILD_PATH:-"../../.build"}        # we prefer .build at the root level, but allow user option
@@ -171,9 +170,9 @@ else
 
        if [[ -d $build_path/lib64 ]]
        then
-               export LD_LIBRARY_PATH=$build_path:$build_path/lib64
+               export LD_LIBRARY_PATH=$build_path:$build_path/lib64:$LD_LIBRARY_PATH
        else
-               export LD_LIBRARY_PATH=$build_path:$build_path/lib
+               export LD_LIBRARY_PATH=$build_path:$build_path/lib:$LD_LIBRARY_PATH
        fi
 fi
 
index 12ab660..acc065d 100644 (file)
@@ -141,7 +141,7 @@ fi
 if (( rebuild ))
 then
        set -e
-       ksh ./rebuild.ksh $nopull | read build_path
+       $SHELL ./rebuild.ksh $nopull | read build_path
        set +e
 else
        build_path=${BUILD_PATH:-"../../.build"}        # we prefer .build at the root level, but allow user option
@@ -156,9 +156,9 @@ fi
 
 if [[ -d $build_path/lib64 ]]
 then
-       export LD_LIBRARY_PATH=$build_path:$build_path/lib64
+       export LD_LIBRARY_PATH=$build_path:$build_path/lib64:$LD_LIBRARY_PATH
 else
-       export LD_LIBRARY_PATH=$build_path:$build_path/lib
+       export LD_LIBRARY_PATH=$build_path:$build_path/lib:$LD_LIBRARY_PATH
 fi
 export LIBRARY_PATH=$LD_LIBRARY_PATH
 export RMR_SEED_RT=./multi.rt
index e78cc4e..62aae3b 100644 (file)
@@ -115,6 +115,7 @@ do
                -b)     rebuild=1; nopull="nopull";;            # build without pulling
                -d)     delay=$2; shift;;
                -m) max_mtype=$2; shift;;
+               -M) force_make=1;;
                -n)     nmsg=$2; shift;;
                -N)     si="";;                                                         # build/run NNG binaries
                -r)     nrcvrs=$2; shift;;
@@ -142,7 +143,7 @@ fi
 if (( rebuild ))
 then
        set -e
-       ksh ./rebuild.ksh $nopull | read build_path
+       $SHELL ./rebuild.ksh $nopull | read build_path
        set +e
 else
        build_path=${BUILD_PATH:-"../../.build"}        # we prefer .build at the root level, but allow user option
@@ -157,9 +158,9 @@ fi
 
 if [[ -d $build_path/lib64 ]]
 then
-       export LD_LIBRARY_PATH=$build_path:$build_path/lib64
+       export LD_LIBRARY_PATH=$build_path:$build_path/lib64:$LD_LIBRARY_PATH
 else
-       export LD_LIBRARY_PATH=$build_path:$build_path/lib
+       export LD_LIBRARY_PATH=$build_path:$build_path/lib:$LD_LIBRARY_PATH
 fi
 export LIBRARY_PATH=$LD_LIBRARY_PATH
 export RMR_SEED_RT=./rr.rt
index bb874f0..d268fd3 100644 (file)
@@ -113,7 +113,7 @@ fi
 if (( rebuild ))
 then
        set -e
-       ksh ./rebuild.ksh $nopull | read build_path
+       $SHELL ./rebuild.ksh $nopull | read build_path
        set +e
 else
        build_path=${BUILD_PATH:-"../../.build"}        # we prefer .build at the root level, but allow user option
@@ -128,9 +128,9 @@ fi
 
 if [[ -d $build_path/lib64 ]]
 then
-       export LD_LIBRARY_PATH=$build_path:$build_path/lib64
+       export LD_LIBRARY_PATH=$build_path:$build_path/lib64:$LD_LIBRARY_PATH
 else
-       export LD_LIBRARY_PATH=$build_path:$build_path/lib
+       export LD_LIBRARY_PATH=$build_path:$build_path/lib:$LD_LIBRARY_PATH
 fi
 export LIBRARY_PATH=$LD_LIBRARY_PATH
 export RMR_SEED_RT=./rts.rt
index f716378..1e30d86 100644 (file)
 
 #include "rmr.h"
 #include "rmr_agnostic.h"
-#include "rmr_nng_private.h"
 
 #define EMULATE_NNG
-#include "test_nng_em.c"
+#define NNG_UNDER_TEST
 #include "sr_nng_static.c"
 
 #include "test_support.c"
index dfc019d..4ef975e 100644 (file)
@@ -29,6 +29,7 @@
 */
 
 #define NO_DUMMY_RMR 1                 // no dummy rmr functions; we don't pull in rmr.h or agnostic.h
+#define NO_EMULATION
 
 #include "rmr_logging.h"
 #include "logging.c"
index 09c4da4..2dbed5c 100644 (file)
@@ -31,6 +31,8 @@
 */
 
 
+#define NO_EMULATION
+
 #include <stdio.h>
 #include <stdlib.h>
 #include <netdb.h>
index 51b8260..f97d89c 100644 (file)
@@ -28,6 +28,8 @@
        Date:           3 April 2019
 */
 
+#define NO_EMULATION
+
 #include <unistd.h>
 #include <stdio.h>
 #include <stdlib.h>
index a3aeb40..08758ad 100644 (file)
@@ -62,6 +62,7 @@
 #include <nng/protocol/pipeline0/push.h>
 #include <nng/protocol/pipeline0/pull.h>
 
+#define NNG_UNDER_TEST 1
 #define EMULATE_NNG
 #include "test_nng_em.c"                                                       // nng/nn emulation (before including things under test)
 
@@ -70,7 +71,6 @@
 #include "rmr_symtab.h"
 #include "rmr_logging.h"
 #include "rmr_agnostic.h"                      // transport agnostic header
-#include "rmr_nng_private.h"                   // transport specific
 
 #include "symtab.c"
 #include "logging.c"
@@ -81,6 +81,7 @@ static void gen_rt( uta_ctx_t* ctx );         // defined in sr_nng_static_test, but use
 
                                                                                        // specific test tools in this directory
 #include "test_support.c"                                      // things like fail_if()
+#include "test_ctx_support.c"                          // specifically geared to creating dummy contex structs
 #include "test_gen_rt.c"
                                                                                        // and finally....
 #include "tools_static_test.c"                         // local test functions pulled directly because of static nature of things
diff --git a/test/rmr_si_api_static_test.c b/test/rmr_si_api_static_test.c
new file mode 100644 (file)
index 0000000..e50a987
--- /dev/null
@@ -0,0 +1,405 @@
+// : 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:           5 April 2019
+*/
+
+#include <unistd.h>
+#include <stdio.h>
+#include <stdlib.h>
+#include <strings.h>
+#include <errno.h>
+#include <string.h>
+#include <stdint.h>
+#include <pthread.h>
+#include <semaphore.h>
+
+#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
+       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;
+       }
+
+       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 "  );
+       errors += fail_if( errno == 0, "rmr_payload_size did not set errno on failure "  );
+
+       v = rmr_payload_size( msg );
+       if( v >= 0 ) {
+               errors += fail_not_equal( v, 2048, "rmr_payload_size returned invalid size (a) instead of expected size (b) "  );
+               errors += fail_if( errno != 0, "rmr_payload_size did not clear errno on success "  );
+       } else {
+               errors += fail_if( v < 0, "rmr_payload_size returned invalid size for good message "  );
+       }
+
+
+
+       v = rmr_get_rcvfd( NULL );
+       errors += fail_if( v >= 0, "rmr_get_rcvfd returned a valid file descriptor when given nil context "  );
+       v = rmr_get_rcvfd( rmc );
+       errors += fail_if( v < 0, "rmr_get_rcvfd did not return a valid file descriptor "  );
+
+       msg2 = rmr_send_msg( NULL, NULL );
+       errors += fail_not_nil( msg2, "send_msg returned msg pointer when given a nil message and context "  );
+
+       msg->state = 0;
+       msg = rmr_send_msg( NULL, msg );
+       errors += fail_if( msg->state == 0, "rmr_send_msg did not set msg state when msg given with nil context "  );
+
+       // --- sends will fail with a no endpoint error until a dummy route table is set, so we test fail case first.
+       msg->len = 100;
+       msg->mtype = 1;
+       msg->state = 999;
+       msg->tp_state = 999;
+       errno = 999;
+       snprintf( msg->payload, 100, "Stand up and cheer from OU to Oh yea! (1)" );
+
+       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
+
+       if( ! rmr_ready( rmc ) ) {
+               fprintf( stderr, "\nPANIC!  rmr isn't showing ready after loading a rt table\n\n" );
+               return errors;
+       }
+
+       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" );
+
+       rmr_free_msg( msg );
+       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;
+               }
+
+               fprintf( stderr, ">>>> len=%d state=%d (%s)\n", msg2->len, msg2->state, msg2->payload );
+               max_tries--;
+       }
+
+
+       // ----- the queue load and disc cb tests should be last! -----------------------------
+       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
+               }
+               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! msg=%d", i );
+
+               msg = rmr_send_msg( rmc, msg );
+               errors += fail_if_nil( msg, "send_msg_ did not return a message on send "  );
+       }
+
+       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, "<INFO> 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
+       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 "  );
+
+       state = rmr_init_trace( rmc, 37 );
+       errors += fail_if_equal( state, 0, "attempt to set trace len in context was not successful "  );
+       errors += fail_not_equal( errno, 0, "attempt to set trace len in context did not clear errno "  );
+
+       msg = rmr_tralloc_msg( rmc, 1024, 17, "1904308620110417" );
+       errors += fail_if_nil( msg, "attempt to allocate message with trace data returned nil message "  );
+       state = rmr_get_trace( msg, wbuf, 17 );
+       errors += fail_not_equal( state, 17, "len of trace data (a) returned after msg allocation was not expected size (b) "  );
+       state = strcmp( wbuf, "1904308620110417" );
+       errors += fail_not_equal( state, 0, "trace data returned after tralloc was not correct "  );
+
+       em_send_failures = 1;
+       send_n_msgs( rmc, 30 );                 // send 30 messages with emulation failures
+       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
+
+
+
+       // --------------- phew, done ------------------------------------------------------------------------------
+
+       if( ! errors ) {
+               fprintf( stderr, "<INFO> all RMr API tests pass\n" );
+       }
+       return !!errors;
+}
diff --git a/test/rmr_si_test.c b/test/rmr_si_test.c
new file mode 100644 (file)
index 0000000..9f49530
--- /dev/null
@@ -0,0 +1,145 @@
+// :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_test.c
+       Abstract:       This tests the whole RMR  SI95 implementation. This driver
+                               includes all of the module specific unit test static files
+                               (e.g. wormhole_static_test.c) and drives the tests contained
+                               there.   The individual modules allow them to be driven by
+                               a standalone driver, and to be maintained separately. We must
+                               test by inclusion because of the static nature of the internal
+                               functions of the library.
+
+       Author:         E. Scott Daniels
+       Date:           18 January 2018         (IMO HRTL)
+*/
+
+#include <stdio.h>
+#include <stdlib.h>
+#include <netdb.h>
+#include <errno.h>
+#include <string.h>
+#include <errno.h>
+#include <pthread.h>
+#include <ctype.h>
+
+
+#include <unistd.h>
+#include <stdio.h>
+#include <stdlib.h>
+#include <strings.h>
+#include <errno.h>
+#include <string.h>
+#include <stdint.h>
+#include <ctype.h>
+#include <sys/epoll.h>
+#include <pthread.h>
+#include <semaphore.h>
+
+#define DEBUG 1
+
+                                                                                       // 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_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 "tools_static_test.c"                         // local test functions pulled directly because of static nature of things
+#include "symtab_static_test.c"
+#include "ring_static_test.c"
+#include "rt_static_test.c"
+#include "wormhole_static_test.c"
+#include "mbuf_api_static_test.c"
+#include "sr_si_static_test.c"
+
+#include "rmr_si_api_static_test.c"
+
+
+/*
+       Drive each of the separate tests and report.
+*/
+int main() {
+       int errors = 0;
+
+       rmr_set_vlevel( 5 );                    // enable all debugging
+
+       fprintf( stderr, "\n<INFO> starting ring tests (%d)\n", errors );
+       errors += ring_test();
+       fprintf( stderr, "<INFO> error count: %d\n", errors );
+
+       fprintf( stderr, "\n<INFO> starting symtab tests\n" );
+       errors += symtab_test( );
+       fprintf( stderr, "<INFO> error count: %d\n", errors );
+
+       fprintf( stderr, "\n<INFO> starting rtable tests\n" );
+       errors += rt_test();                            // route table tests
+       fprintf( stderr, "<INFO> error count: %d\n", errors );
+
+       fprintf( stderr, "\n<INFO> starting wormhole tests\n" );
+       errors += worm_test();                          // test wormhole funcitons
+       fprintf( stderr, "<INFO> error count: %d\n", errors );
+
+       fprintf( stderr, "\n<INFO> starting tool tests\n" );
+       errors += tools_test();
+       fprintf( stderr, "<INFO> error count: %d\n", errors );
+
+       fprintf( stderr, "\n<INFO> starting mbuf api tests\n" );
+       errors +=  mbuf_api_test( );
+       fprintf( stderr, "<INFO> error count: %d\n", errors );
+
+       fprintf( stderr, "\n<INFO> starting send/receive tests\n" );
+       errors += sr_si_test();                         // test the send/receive static functions
+       fprintf( stderr, "<INFO> error count: %d\n", errors );
+
+
+       fprintf( stderr, "\n<INFO> starting RMr API tests\n" );
+       errors += rmr_api_test();
+
+/// ---- all ok above here
+/*
+       fprintf( stderr, "\n<INFO> run RMr API tests with src name only env var set\n" );
+       setenv( "RMR_SRC_NAMEONLY", "1", 1 );
+       errors += rmr_api_test();
+       fprintf( stderr, "<INFO> error count: %d\n", errors );
+*/
+
+       if( errors == 0 ) {
+               fprintf( stderr, "<PASS> all tests were OK\n\n" );
+       } else {
+               fprintf( stderr, "<FAIL> %d modules reported errors\n\n", errors );
+       }
+
+       return !!errors;
+}
index 9559004..d87a743 100644 (file)
@@ -103,6 +103,7 @@ static int rt_test( ) {
        rtable_ent_t*   rte;    // route table entries from table
        rtable_ent_t*   rte2;
        endpoint_t*     ep;                     // endpoint added
+       endpoint_t*     ep2;
        int more = 0;                   // more flag from round robin
        int errors = 0;                 // number errors found
        int     i;
@@ -122,9 +123,13 @@ static int rt_test( ) {
        int             state;
        char    *buf;
        char*   seed_fname;             // seed file
-       nng_socket nn_sock;             // this is a struct in nng, so difficult to validate
+       SOCKET_TYPE     nn_sock;        // differnt in each transport (nng == struct, SI/Nano == int)
        rmr_mbuf_t*     mbuf;           // message for meid route testing
 
+       #ifndef NNG_UNDER_TEST
+               si_ctx_t* si_ctx = NULL;
+       #endif
+
        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, 0644 );
        if( i >= 0 ) {
@@ -132,12 +137,12 @@ static int rt_test( ) {
                close( i );
        }
 
-                                                       
+
        /*
                The hacky code below calls the necessary rmr functions to create a route table
                as though the following were read and parsed by the rmr functions. (This tests
                the individual funcitons and avoids writing another parser, so it's not pretty.)
-       
+
                mse | 0 | 0 | yahoo.com:4561,localhost:4562
                mse | 1 | 0 | localhost:4560,localhost:4568,localhost:4569; localhost:4561,localhost:4562
                mse | 2 | 0 | localhost:4563,localhost:4564
@@ -224,7 +229,7 @@ static int rt_test( ) {
                c1 = count_entries( rt, 1 );
                c2 = count_entries( crt, 1 );
                errors += fail_not_equal( c1, c2, "cloned (endpoints) table entries space 1 count (b) did not match original table count (a)" );
-       
+
                c2 = count_entries( crt, 0 );
                errors += fail_not_equal( c2, 0, "cloned (endpoints) table entries space 0 count (a) was not zero as expected" );
                uta_rt_drop( crt );
@@ -238,13 +243,26 @@ static int rt_test( ) {
                c1 = count_entries( rt, 0 );
                c2 = count_entries( crt, 0 );
                errors += fail_not_equal( c1, c2, "cloned (all) table entries space 0 count (b) did not match original table count (a)" );
-       
+
                c1 = count_entries( rt, 1 );
                c2 = count_entries( crt, 1 );
                errors += fail_not_equal( c1, c2, "cloned (all) table entries space 1 count (b) did not match original table count (a)" );
                uta_rt_drop( crt );
        }
-       
+
+       #ifdef NNG_UNDER_TEST
+               if( (ctx = (uta_ctx_t *) malloc( sizeof( uta_ctx_t ) )) != NULL ) {             // get a "context" needed for si testing
+                       memset( ctx, 0, sizeof( *ctx ) );
+                       ctx->rtable = rt;
+               } else {
+                       fprintf( stderr, "<FAIL> cannot acllocate a context, cannot continue rtable tests\n" );
+                       return errors;
+               }
+       #else
+               ctx = mk_dummy_ctx();
+       #endif
+
+       ctx->rtable = rt;
 
        ep = uta_get_ep( rt, "localhost:4561" );
        errors += fail_if_nil( ep, "end point (fetch by name)" );
@@ -252,12 +270,31 @@ static int rt_test( ) {
        errors += fail_not_nil( ep, "end point (fetch by name with bad name)" );
 
        ep = NULL;
-       state = uta_epsock_byname( rt, "localhost:4561", &nn_sock, &ep );               // this should be found
+       #ifdef NNG_UNDER_TEST
+               state = uta_epsock_byname( rt, "localhost:4561", &nn_sock, &ep );               // this should be found
+       #else
+               state = uta_epsock_byname( ctx, "localhost:4561", &nn_sock, &ep );      // this should be found
+       #endif
        errors += fail_if_equal( state, 0, "socket (by name)" );
        errors += fail_if_nil( ep, "epsock_byname did not populate endpoint pointer when expected to" );
        //alt_value = uta_epsock_byname( rt, "localhost:4562" );                        // we might do a memcmp on the two structs, but for now nothing
        //errors += fail_if_equal( value, alt_value, "app1/app2 sockets" );
 
+       #if  NNG_UNDER_TEST
+               state = uta_epsock_byname( NULL, "localhost:4561", &nn_sock, &ep );             // test coverage on nil checks
+       #else
+               state = uta_epsock_byname( NULL, "localhost:4561", &nn_sock, &ep );
+       #endif
+       errors += fail_not_equal( state, 0, "socket (by name) nil check returned true" );
+
+       ep->open = 1;
+       #if  NNG_UNDER_TEST
+               state = uta_epsock_byname( rt, "localhost:4561", &nn_sock, NULL );              // test coverage on nil checks
+       #else
+               state = uta_epsock_byname( ctx, "localhost:4561", &nn_sock, NULL );
+       #endif
+       errors += fail_if_equal( state, 0, "socket (by name) open ep check returned false" );
+
 
        // --- test that the get_rte function finds expected keys, and retries to find 'bad' sid attempts for valid mtypes with no sid
        rte = uta_get_rte( rt, 0, 1, TRUE );                    // s=0 m=1 is defined, so this should return a pointer
@@ -286,14 +323,20 @@ static int rt_test( ) {
        rte = uta_get_rte( rt, 12, 3, FALSE );                  // this combo does not exist and should fail when alt-key is not allowed (false)
        errors += fail_not_nil( rte, "get_rte returned a pointer for s=12, m=3, false" );
 
-       rte = uta_get_rte( rt, 12, 3, TRUE );                   // this should return the entry for the 3/-1 combination 
+       rte = uta_get_rte( rt, 12, 3, TRUE );                   // this should return the entry for the 3/-1 combination
        errors += fail_if_nil( rte, "get_rte did not return a pointer for s=12, m=3, true" );
 
+
        alt_value = -1;
        rte = uta_get_rte( rt, 0, 1, FALSE );                   // get an rte for the next loop
        if( rte ) {
                for( i = 0; i < 10; i++ ) {                                                                     // round robin return value should be different each time
-                       value = uta_epsock_rr( rte, 0, &more, &nn_sock, &ep );          // msg type 1, group 1
+                       #ifdef NNG_UNDER_TEST
+                               value = uta_epsock_rr( rte, 0, &more, &nn_sock, &ep );          // msg type 1, group 1
+                       #else
+                               value = uta_epsock_rr( ctx, rte, 0, &more, &nn_sock, &ep );
+                       #endif
+
                        errors += fail_if_equal( value, alt_value, "round robiin sockets with multiple end points" );
                        errors += fail_if_false( more, "more for mtype==1" );
                        alt_value = value;
@@ -304,7 +347,12 @@ static int rt_test( ) {
        rte = uta_get_rte( rt, 0, 3, FALSE );                           // get an rte for the next loop
        if( rte ) {
                for( i = 0; i < 10; i++ ) {                                                             // this mtype has only one endpoint, so rr should be same each time
-                       value = uta_epsock_rr( rte, 0, NULL, &nn_sock, &ep );           // also test ability to deal properly with nil more pointer
+                       #ifdef NNG_UNDER_TEST
+                               value = uta_epsock_rr( rte, 0, NULL, &nn_sock, &ep );           // also test ability to deal properly with nil more pointer
+                       #else
+                               value = uta_epsock_rr( ctx, rte, 0, NULL, &nn_sock, &ep );
+                       #endif
+
                        if( i ) {
                                errors += fail_not_equal( value, alt_value, "round robin sockets with one endpoint" );
                                errors += fail_not_equal( more, -1, "more value changed in single group instance" );
@@ -314,13 +362,29 @@ static int rt_test( ) {
        }
 
        rte = uta_get_rte( rt, 11, 3, TRUE );
-       state = uta_epsock_rr( rte, 22, NULL, NULL, &ep );
+       #ifdef NNG_UNDER_TEST
+               state = uta_epsock_rr( rte, 22, NULL, NULL, &ep );
+       #else
+               state = uta_epsock_rr( ctx, rte, 22, NULL, NULL, &ep );
+       #endif
        errors += fail_if_true( state, "uta_epsock_rr returned bad (non-zero) state when given nil socket pointer" );
 
 
        uta_rt_clone( NULL );                                                           // verify null parms don't crash things
        uta_rt_drop( NULL );
-       uta_epsock_rr( NULL, 0,  &more, &nn_sock, &ep );                        // drive null case for coverage
+       #ifdef NNG_UNDER_TEST
+               uta_epsock_rr( NULL, 0,  &more, &nn_sock, &ep );                        // drive null case for coverage
+               state = uta_epsock_rr( rte, 22, NULL, NULL, &ep );
+       #else
+               state = uta_epsock_rr( NULL, NULL, 0,  &more, &nn_sock, &ep );                  // drive null case for coverage
+               errors += fail_not_equal( state, 0, "uta_epsock_rr did not return false when given nil ctx" );
+
+               state = uta_epsock_rr( ctx, NULL, 0,  &more, &nn_sock, &ep );
+               errors += fail_not_equal( state, 0, "uta_epsock_rr did not return false when given nil rte" );
+
+               state = uta_epsock_rr( ctx, rte, 10000,  &more, &nn_sock, &ep );
+               errors += fail_not_equal( state, 0, "uta_epsock_rr did not return false when given invalid group number" );
+       #endif
        uta_add_rte( NULL, 99, 1 );
        uta_get_rte( NULL, 0, 1000, TRUE );
 
@@ -342,9 +406,8 @@ static int rt_test( ) {
        uta_rt_drop( rt );
        rt = NULL;
 
-       if( (ctx = (uta_ctx_t *) malloc( sizeof( uta_ctx_t ) )) != NULL ) {
-               memset( ctx, 0, sizeof( *ctx ) );
 
+       if( ctx ) {
                if( (seed_fname = getenv( "RMR_SEED_RT" )) != NULL ) {
                        read_static_rt( ctx, 0 );
                        rt = ctx->rtable;
@@ -366,11 +429,58 @@ static int rt_test( ) {
        pthread_mutex_init( &ep->gate, NULL );
        ep->name = strdup( "worm" );
        ep->addr = NULL;
-       state = uta_link2( ep );
-       errors += fail_if_true( state, "link2 did not return false when given nil pointers" );
+       #ifdef NNG_UNDER_TEST
+               state = uta_link2( ep );
+       #else
+               state = uta_link2( ctx, ep );
+       #endif
+       errors += fail_if_true( state, "link2 did not return false when given a bad target name" );
+
+       #ifdef NNG_UNDER_TEST
+               state = uta_link2( NULL );
+       #else
+               state = uta_link2( ctx, NULL );
+               errors += fail_if_true( state, "link2 did not return false when given nil ep pointer" );
+
+               state = uta_link2( NULL, ep );
+       #endif
+       errors += fail_if_true( state, "link2 did not return false when given nil pointer" );
+
+       ep->name = strdup( "localhost:5512" );
+       ep->open = 1;
+       #ifdef NNG_UNDER_TEST
+               state = uta_link2( ep );                        // drive for coverage
+       #else
+               state = uta_link2( ctx, ep );
+       #endif
+       errors += fail_if_false( state, "link2 did returned false when given open ep" );
+
+       #ifndef NNG_UNDER_TEST
+               ep->open = 0;                                                   // context is used only if ep not open, so to check this test close the ep
+               state = rt_link2_ep( NULL, ep );
+               errors += fail_if_true( state, "rt_link2_ep returned true when given bad context" );
+
+               state = rt_link2_ep( ctx, NULL );
+               errors += fail_if_true( state, "rt_link2_ep returned true when given bad ep" );
+
+               ep->open = 1;
+               state = rt_link2_ep( ctx, ep );
+               errors += fail_if_false( state, "rt_link2_ep returned false when given an open ep" );
+
+               ep->open = 0;
+               state = rt_link2_ep( ctx, ep );
+               errors += fail_if_false( state, "rt_link2_ep returned false when given a closed ep" );
+
+               ep->open = 1;
+               uta_ep_failed( ep );
+               errors += fail_if_true( ep->open, "uta_ep_failed didn't set open flag to false" );
+
+       #endif
+
 
        // ----------------- test the meid support for looking up an endpoint based on the meid in the message -----
 
+       ctx->rtable = NULL;
        ctx->my_name = strdup( "my_host_name" );                // set up to load a rtable
        ctx->my_ip = strdup( "192.168.1.30" );
        gen_rt( ctx );                                                                  // generate a route table with meid entries and hang off ctx
@@ -379,15 +489,60 @@ static int rt_test( ) {
        mbuf->len = 100;
        rmr_str2meid( mbuf, "meid1" );                                  // id that we know is in the map
 
-       ep = NULL;                                                                              // force to nil so we see it go non-nil
-       state = epsock_meid( ctx->rtable, mbuf, &nn_sock, &ep );
-       errors += fail_if_nil( ep, "ep was nil when looking up ep with known meid in message" );
-       errors += fail_not_equal( state, 1, "state was not true when looking up ep with known meid in message" );
+       #ifdef NNG_UNDER_TEST
+               ep = NULL;                                                                              // force to nil so we see it go non-nil
+               state = epsock_meid( ctx->rtable, mbuf, &nn_sock, &ep );
+               errors += fail_if_nil( ep, "ep was nil when looking up ep with known meid in message" );
+               errors += fail_not_equal( state, 1, "state was not true when looking up ep with known meid in message" );
+
+               rmr_str2meid( mbuf, "XXXmeid1" );                               // id that we know is NOT in the map
+               state = epsock_meid( ctx->rtable, mbuf, &nn_sock, &ep );
+               // it is NOT a valid check to test ep for nil -- epsock_mied doesn't guarentee ep is set/cleared when state is false
+               errors += fail_not_equal( state, 0, "state was not false when looking up ep with unknown meid in message" );
+       #else
+               ep = NULL;                                                                              // force to nil so we see it go non-nil
+               state = epsock_meid( ctx, ctx->rtable,  mbuf, &nn_sock, &ep );
+               errors += fail_if_nil( ep, "ep was nil when looking up ep with known meid in message" );
+               errors += fail_not_equal( state, 1, "state was not true when looking up ep with known meid in message" );
+
+               state = epsock_meid( ctx, ctx->rtable,  mbuf, &nn_sock, &ep );          // a second call to drive open == true check for coverage
+               errors += fail_if_nil( ep, "ep was nil when looking up ep with known meid in message; on open ep" );
+               errors += fail_not_equal( state, 1, "state was not true when looking up ep with known meid in message; on open ep" );
+
+               rmr_str2meid( mbuf, "XXXmeid1" );                               // id that we know is NOT in the map
+               state = epsock_meid( ctx, ctx->rtable, mbuf, &nn_sock, &ep );
+               // it is NOT a valid check to test ep for nil -- epsock_mied doesn't guarentee ep is set/cleared when state is false
+               errors += fail_not_equal( state, 0, "state was not false when looking up ep with unknown meid in message" );
+
+               state = epsock_meid( NULL, ctx->rtable,  mbuf, &nn_sock, &ep );
+               errors += fail_not_equal( state, 0, "epsock_meid returned true when given nil context" );
+
+               state = epsock_meid( ctx, ctx->rtable,  mbuf, NULL, &ep );
+               errors += fail_not_equal( state, 0, "epsock_meid returned true when given nil socket pointer" );
+       #endif
+
+
+       // ------------- si only; fd to ep conversion functions ---------------------------------------------------------
+       #ifndef NNG_UNDER_TEST
+               ep2 = (endpoint_t *) malloc( sizeof( *ep ) );
+
+               fd2ep_init( ctx );
+               fd2ep_add( ctx, 10, ep2 );
+
+               ep = fd2ep_get( ctx, 10 );
+               errors += fail_if_nil( ep, "fd2ep did not return pointer for known mapping" );
+               errors += fail_if_false( ep == ep2,  "fd2ep did not return same pointer that was added" );
+
+               ep = fd2ep_get( ctx, 20 );
+               errors += fail_not_nil( ep, "fd2ep did returned a pointer for unknown mapping" );
+
+               ep = fd2ep_del( ctx, 10 );
+               errors += fail_if_nil( ep, "fd2ep delete did not return pointer for known mapping" );
+               errors += fail_if_false( ep == ep2,  "fd2ep delete did not return same pointer that was added" );
 
-       rmr_str2meid( mbuf, "XXXmeid1" );                               // id that we know is NOT in the map
-       state = epsock_meid( ctx->rtable, mbuf, &nn_sock, &ep );
-       // it is NOT a valid check to test ep for nil -- epsock_mied doesn't guarentee ep is set/cleared when state is false
-       errors += fail_not_equal( state, 0, "state was not false when looking up ep with unknown meid in message" );
+               ep = fd2ep_del( ctx, 20 );
+               errors += fail_not_nil( ep, "fd2ep delete returned a pointer for unknown mapping" );
+       #endif
 
        return !!errors;                        // 1 or 0 regardless of count
 }
diff --git a/test/run_app_tests b/test/run_app_tests
new file mode 100644 (file)
index 0000000..21064d9
--- /dev/null
@@ -0,0 +1,54 @@
+#!/usr/env bash
+# vim: ts=4 sw=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.
+#==================================================================================
+#
+
+# this is a simple wrapper until we figure out why CMake seems unable to start
+# the run_all script in the app test directory. Even after that it will likely
+# be needed because it seems impossible to set environment vars from CMake for
+# the test script which makes testing alternate install locations impossible.
+# So, we must jump some hoops to allow for that...
+
+# Hoop:
+# It seems that we cannot supply env vars on the CMake generated command :(
+# To deal with this, all leading positional parms of the form foo=bar are
+# looked at and if we like it we'll export it before starting the test.
+
+while [[ $1 == *"="* ]]
+do
+       case ${1%%=*} in
+               LD_LIBRARY_PATH)
+                       export LD_LIBRARY_PATH=${1##*=}
+                       ;;
+
+               C_INCLUDE_PATH)
+                       export C_INCLUDE_PATH=${1##*=}
+                       ;;
+
+               LIBRARY_PATH)
+                       export LIBRARY_PATH=${1##*=}
+                       ;;
+       esac
+
+       shift
+done
+
+
+set -e
+cd app_test
+bash ./run_all.ksh -S  # build CI likely doesn't have ksh; Run SI tests
diff --git a/test/sr_si_static_test.c b/test/sr_si_static_test.c
new file mode 100644 (file)
index 0000000..5768f3e
--- /dev/null
@@ -0,0 +1,252 @@
+// : vi ts=4 sw=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:       sr_si_static_test.c
+       Abstract:       Test the send/receive funcitons. These are meant to be included at compile
+                               time by the test driver.
+
+       Author:         E. Scott Daniels
+       Date:           21 February 2020
+*/
+
+#include <unistd.h>
+#include <stdio.h>
+#include <stdlib.h>
+#include <strings.h>
+#include <errno.h>
+#include <string.h>
+#include <stdint.h>
+#include <pthread.h>
+#include <semaphore.h>
+
+#include "rmr.h"
+#include "rmr_agnostic.h"
+
+// ----------- local test support ----------------------------------------------------------
+#define CLONE  1                       // convenience constants for payload realloc tests
+#define NO_CLONE 0
+#define COPY 1
+#define NO_COPY 0
+
+/*
+       Drive the send and receive functions.  We also drive as much of the route
+       table collector as is possible without a real rtg process running somewhere.
+
+       Send and receive functions are indirectly exercised from the rmr_si_static_test
+       module as it tests the user facing send/receive/call/rts functions. These tests
+       should exercise specific cases for the internal functions as they will not
+       specifically be driven elsewhere.
+
+       This requires the gen_rt funcition that is in the test_gen_rt module and should
+       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*      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             size;
+       int             i;
+       void*   p;
+       char*   payload_str;
+
+       ctx = mk_dummy_ctx();                                                                   // in the si world we need some rings in the context
+
+       ctx->max_plen = RMR_MAX_RCV_BYTES + sizeof( uta_mhdr_t );
+       ctx->max_mlen = ctx->max_plen + sizeof( uta_mhdr_t );
+       ctx->my_name = strdup( "dummy-test" );
+       ctx->my_ip = strdup( "30.4.19.86:1111" );
+       uta_lookup_rtg( ctx );
+
+       gen_rt( ctx );                                                          // forces a static load with some known info since we don't start the rtc()
+       gen_rt( ctx );                                                          // force a second load to test cloning
+
+       p = rt_ensure_ep( NULL, "foo" );                                // drive for coverage
+       errors += fail_not_nil( p,  "rt_ensure_ep did not return nil when given nil route table" );
+
+       state = rmr_ready( NULL );
+       errors += fail_if_true( state, "reported ready when given a nil context" );
+       state = rmr_ready( ctx );
+       errors += fail_if_false( state, "reported not ready when it should be" );
+
+       /*
+               rcv_msg under SI is deprecated -- do not attempt to call
+       mbuf = rcv_msg( ctx, NULL );
+       errors += fail_if_nil( mbuf, "no mbuf returned on receive test" );
+       */
+
+       mbuf = rmr_alloc_msg( ctx, 2048 );
+       mbuf->len = 10;
+       mbuf->mtype = 1;
+
+       mb2 = clone_msg( mbuf );
+       errors += fail_if_nil( mb2, "clone message returned nil pointer" );
+       errors += fail_not_equal( mbuf->flags, mb2->flags, "clone did not duplicate flags" );
+       errors += fail_not_equal( mbuf->alloc_len, mb2->alloc_len, "clone did not dup alloc-len" );
+       errors += fail_not_equal( mbuf->state, mb2->state, "clone did not dup state" );
+       rmr_free_msg( mb2 );
+
+       mbuf = rmr_send_msg( NULL, mbuf );
+       errors += fail_if_nil( mbuf, "send with nil context but buffere didn't return buffer" );
+       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 );
+       }
+
+       //size = 2048 - em_hdr_size();          // emulated receive allocates 2K buffers -- subtract off header size
+       size = 2048;
+       state = rmr_payload_size( mbuf );
+       errors += fail_not_equal( state, size, "payload size didn't return expected value" );   // receive should always give 4k buffer
+
+       rmr_free_msg( mbuf );
+
+
+       // ---- drive rtc in a 'static' (not pthreaded) mode to get some coverage; no 'results' to be verified -----
+       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 );
+       if( i >= 0 ) {
+               write( i, "2\n", 2 );
+               close( i );
+       }
+       ctx->shutdown = 1;                      // should force rtc to quit on first pass
+       rtc( NULL );                            // coverage test with nil pointer
+/*
+       rtc( ctx );
+
+       setenv( "RMR_RTG_SVC", "4567", 1 );             // drive for edge case coverage to ensure no nil pointer etc
+       rtc( ctx );
+       setenv( "RMR_RTG_SVC", "tcp:4567", 1 );
+       rtc( ctx );
+       setenv( "RMR_RTG_SVC", "tcp:4567:error", 1 );
+       rtc( ctx );
+*/
+
+       // ------------- reallocation tests ------------------------------------------------------------
+       // we use mk_populated_msg() to create a message with mid/sid/plen pushed into the transport
+       // header to simulate a message having been sent and received which is what causes this data
+       // to push into the wire packet.
+
+       payload_str = "Stand Up and Cheer; OU78-82";
+
+
+       mbuf = mk_populated_msg( 1024, 0, 99, 100, strlen( payload_str ) );
+       memcpy( mbuf->payload, payload_str, mbuf->len );
+       mb2 = realloc_payload( mbuf, 512, NO_COPY, NO_CLONE );
+       errors += fail_if_nil( mb2, "realloc_payload (no copy) returned a nil pointer when reallocating with smaller size" );
+       errors += fail_if_false( mbuf == mb2, "non-clone realloc payload (no copy) of smaller size did not return the same buffer" );
+
+       mb2 = realloc_payload( NULL, 512, NO_COPY, NO_CLONE );
+       errors += fail_not_nil( mb2, "realloc payload did not return nil pointer when passed nil mbuf" );
+
+       mb2 = realloc_payload( mbuf, 0, NO_COPY, NO_CLONE );
+       errors += fail_not_nil( mb2, "realloc payload did not return nil pointer when passed bad len" );
+
+       fprintf( stderr, "<TEST> no copy/no clone test starts\n" );
+       mb2 = realloc_payload( mbuf, 2048, NO_COPY, NO_CLONE );
+       errors += fail_if_false( mbuf == mb2, "realloc payload (no copy) of larger size did not return the same msg buffer(1)" );
+       errors += fail_not_equal( mb2->mtype, -1, "realloc payload (no copy) did not reset mtype(a) to expected(b) value" );
+       errors += fail_not_equal( mb2->sub_id, -1, "realloc payload (no copy) did not reset sub-id(a) to expected(b) value" );
+       errors += fail_if_nil( mb2, "realloc payload returned (no copy) a nil pointer when increasing payload len" );
+       errors += fail_not_equal( mb2->len, 0, "realloc payload payload len(a) not expected(b):" );
+       errors += fail_not_equal( rmr_payload_size( mb2), 2048, "realloc payload alloc len(a) not expected(b)" );
+
+       fprintf( stderr, "<TEST> copy/no clone test starts\n" );
+       mbuf = mk_populated_msg( 1024, 0, 99, 100, strlen( payload_str ) );
+       memcpy( mbuf->payload, payload_str, mbuf->len );
+       mb2 = realloc_payload( mbuf, 2048, COPY, NO_CLONE );
+       errors += fail_if_false( mbuf == mb2, "non-clone realloc payload (copy) of larger size did not return the same msg buffer(2)" );
+       errors += fail_if_nil( mb2, "realloc payload (copy) returned a nil pointer when increasing payload len)" );
+       errors += fail_not_equal( mb2->mtype, 99, "realloc payload (copy) did not reset mtype(a) to expected(b) value" );
+       errors += fail_not_equal( mb2->sub_id, 100, "realloc payload (copy) did not reset sub-id(a) to expected(b) value" );
+       errors += fail_if_equal( mb2->len, 0, "realloc payload (copy) msg len(a) not expected(b)" );
+       errors += fail_not_equal( rmr_payload_size( mb2), 2048, "realloc payload (copy) alloc len(a) not expected(b)" );
+       errors += fail_not_equal( strncmp( payload_str, mb2->payload, strlen( payload_str )), 0, "realloc payload(copy) didn't copy payload" );
+
+       fprintf( stderr, "<TEST> copy/clone test starts requested buffer smaller than original\n" );
+       mbuf = mk_populated_msg( 1024, 0, 99, 100, strlen( payload_str ) );
+       memcpy( mbuf->payload, payload_str, mbuf->len );
+       mb2 = realloc_payload( mbuf, 512, COPY, CLONE );
+       errors += fail_if_true( mbuf == mb2, "realloc payload (clone+copy) of larger size did not return different message buffers" );
+       errors += fail_if_nil( mb2, "realloc payload (clone+copy) returned a nil pointer when increasing payload len)" );
+       errors += fail_not_equal( mb2->mtype, 99, "realloc payload (clone+copy) did not reset mtype(a) to expected(b) value" );
+       errors += fail_not_equal( mb2->sub_id, 100, "realloc payload (clone+copy) did not reset sub-id(a) to expected(b) value" );
+       errors += fail_not_equal( mb2->len, strlen( payload_str ), "realloc payload (clone+copy) msg len(a) not expected(b)" );
+       errors += fail_not_equal( rmr_payload_size( mb2), 1024, "realloc payload (clone+copy) alloc len(a) not expected(b)" );
+       errors += fail_not_equal( strncmp( payload_str, mb2->payload, strlen( payload_str )), 0, "realloc payload(clone+copy) didn't copy payload" );
+
+       // with a clone, we must verify that original message looks sane too
+       errors += fail_not_equal( mbuf->mtype, 99, "realloc payload (clone+copy) validation of unchanged mbuf->mtype fails" );
+       errors += fail_not_equal( mbuf->sub_id, 100, "realloc payload (clone+copy) validation of unchanged mbuf->subid fails" );
+       errors += fail_not_equal( mbuf->len, strlen( payload_str ), "realloc payload (clone+copy) validation of unchanged payload len fails" );
+       errors += fail_not_equal( rmr_payload_size( mbuf ), 1024, "realloc payload (clone+copy) validation of unchanged alloc length fails" );
+       errors += fail_not_equal( strncmp( payload_str, mbuf->payload, strlen( payload_str )), 0, "realloc payload(clone+copy) validation of unchanged payload fails" );
+
+
+       fprintf( stderr, "<TEST> copy/clone test starts requested buf is larger than original\n" );
+       mbuf = mk_populated_msg( 1024, 0, 99, 100, strlen( payload_str ) );
+       memcpy( mbuf->payload, payload_str, mbuf->len );
+       mb2 = realloc_payload( mbuf, 2048, COPY, CLONE );
+       errors += fail_if_true( mbuf == mb2, "realloc payload(clone+copy/lg) of larger size did not return different message buffers" );
+       errors += fail_if_nil( mb2, "realloc payload (clone+copy/lg) returned a nil pointer when increasing payload len)" );
+       errors += fail_not_equal( mb2->mtype, 99, "realloc payload (clone+copy/lg) did not reset mtype(a) to expected(b) value" );
+       errors += fail_not_equal( mb2->sub_id, 100, "realloc payload (clone+copy/lg) did not reset sub-id(a) to expected(b) value" );
+       errors += fail_not_equal( mb2->len, strlen( payload_str ), "realloc payload (clone+copy/lg) msg len(a) not expected(b)" );
+       errors += fail_not_equal( rmr_payload_size( mb2), 2048, "realloc payload (clone+copy/lg) alloc len(a) not expected(b)" );
+       errors += fail_not_equal( strncmp( payload_str, mb2->payload, strlen( payload_str )), 0, "realloc payload(clone+copy/lg) didn't copy payload" );
+
+       // with a clone, we must verify that original message looks sane too
+       errors += fail_not_equal( mbuf->mtype, 99, "realloc payload (clone+copy/lg) validation of unchanged mbuf->mtype fails" );
+       errors += fail_not_equal( mbuf->sub_id, 100, "realloc payload (clone+copy/lg) validation of unchanged mbuf->subid fails" );
+       errors += fail_not_equal( mbuf->len, strlen( payload_str ), "realloc payload (clone+copy/lg) validation of unchanged payload len fails" );
+       errors += fail_not_equal( rmr_payload_size( mbuf ), 1024, "realloc payload (clone+copy/lg) validation of unchanged alloc length fails" );
+       errors += fail_not_equal( strncmp( payload_str, mbuf->payload, strlen( payload_str )), 0, "realloc payload(clone+copy/lg) validation of unchanged payload fails" );
+
+       // original message should be unharmed, and new message should have no type/sid or payload len; total alloc len should be requested enlargement
+       fprintf( stderr, "<TEST> no copy/clone test starts requested buf is larger than original\n" );
+       mbuf = mk_populated_msg( 1024, 0, 99, 100, strlen( payload_str ) );
+       memcpy( mbuf->payload, payload_str, mbuf->len );
+       mb2 = realloc_payload( mbuf, 2048, NO_COPY, CLONE );
+       errors += fail_if_true( mbuf == mb2, "realloc payload (clone+nocopy) of larger size did not return different message buffers" );
+       errors += fail_if_nil( mb2, "realloc payload (clone+nocopy) returned a nil pointer when increasing payload len)" );
+       errors += fail_not_equal( mb2->mtype, -1, "realloc payload (clone+nocopy) did not reset mtype(a) to expected(b) value" );
+       errors += fail_not_equal( mb2->sub_id, -1, "realloc payload (clone+nocopy) did not reset sub-id(a) to expected(b) value" );
+       errors += fail_not_equal( mb2->len, 0, "realloc payload (clone+nocopy) msg len(a) not expected(b)" );
+       errors += fail_not_equal( rmr_payload_size( mb2 ), 2048, "realloc payload (clone+nocopy) alloc len(a) not expected(b)" );
+       errors += fail_if_equal( strncmp( payload_str, mb2->payload, strlen( payload_str )), 0, "realloc payload(clone+nocopy) copied payload when not supposed to" );
+
+       // with a clone, we must verify that original message looks sane too
+       errors += fail_not_equal( mbuf->mtype, 99, "realloc payload (clone+nocopy) validation of unchanged mbuf->mtype fails" );
+       errors += fail_not_equal( mbuf->sub_id, 100, "realloc payload (clone+nocopy) validation of unchanged mbuf->subid fails" );
+       errors += fail_not_equal( mbuf->len, strlen( payload_str ), "realloc payload (clone+nocopy) validation of unchanged payload len fails" );
+       errors += fail_not_equal( rmr_payload_size( mbuf ), 1024, "realloc payload (clone+nocopy) validation of unchanged alloc length fails" );
+       errors += fail_not_equal( strncmp( payload_str, mbuf->payload, strlen( payload_str )), 0, "realloc payload (clone+nocopy) validation of unchanged payload fails" );
+
+
+       return !!errors;
+}
index 7d5a39c..c512966 100644 (file)
@@ -31,7 +31,6 @@
 #include "rmr_symtab.h"
 //  -- parent must include if needed #include "../src/common/src/symtab.c"
 
-#include "test_support.c"
 
 #ifndef GOOD
 #define GOOD 0
index b755e9c..1971317 100644 (file)
 */
 
 #define NO_DUMMY_RMR 1                 // no dummy rmr functions; we don't pull in rmr.h or agnostic.h
+#define NO_EMULATION
+#define NO_PRIVATE_HEADERS
 
+#include <rmr.h>
+#include <rmr_agnostic.h>
+#include "test_support.c"
 #include "rmr_symtab.h"
-#include "symtab.c"
 
-#include "test_support.c"
+#include "symtab.c"                                                    // module under test
+
 
 int state = GOOD;                                                      // overall pass/fail state 0==fail
 int counter;                                                           // global counter for for-each tests
diff --git a/test/test_common_em.c b/test/test_common_em.c
new file mode 100644 (file)
index 0000000..d2977f6
--- /dev/null
@@ -0,0 +1,202 @@
+/*
+==================================================================================
+       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.
+==================================================================================
+*/
+
+/*
+       Mnemonic:       test_common_em.c
+       Abstract:       This supplies some dummy emulation functions that are common
+                               to any of the emulation code. This file should be inlucded
+                               by the emulation code, and not the test programme.
+
+                               This also includes dummy struct defs so that we can simulate
+                               returning messages and message buffers and some control
+                               functions which can be used to taylor the emulation behavour
+                               during the test.
+
+       Date:           21 February 2020
+       Author:         E. Scott Daniels
+*/
+
+#ifndef _em_common_c
+#define _em_common_c
+
+
+static int em_send_failures = 0;       // test programme can set this to emulate eagain send failures
+static int em_timeout = -1;                    // set by set socket option
+static int em_mtc_msgs = 0;                    // set to generate 'received' messages with mt-call header data
+static int return_value = 0;           // functions should return this value
+static int rcv_count = 0;                      // receive counter for transaction id to allow test to rest
+static int rcv_delay = 0;                      // forced delay before call to rcvmsg starts to work
+
+static int gates_ok = 0;
+static pthread_mutex_t rcv_gate;
+static int em_gen_long_hostname = 0;           // if set the emulated hostname generates a longer name (>40 char)
+
+/*
+       Simulated v1 message for receive to return. This needs to match the RMr header
+       so that we can fill in length, type and xaction id things.
+#define MSG_VER 1
+struct em_msg {
+       int32_t mtype;                                          // message type  ("long" network integer)
+       int32_t plen;                                           // payload length
+       int32_t rmr_ver;                                        // our internal message version number
+       unsigned char xid[32];                          // space for user transaction id or somesuch
+       unsigned char sid[32];                          // sender ID for return to sender needs
+       unsigned char src[16];                          // name of the sender (source)
+       unsigned char meid[32];                         // managed element id.
+       struct timespec ts;                                     // timestamp ???
+};
+*/
+
+/*
+       v2 message; should be able to use it for everything that is set up here as
+       we don't add a payload even if setting a v1 type.
+*/
+#define ALT_MSG_VER 1  // alternate every so often
+#define MSG_VER 3              // default version to insert
+struct em_msg {
+       int32_t mtype;                                          // message type  ("long" network integer)
+       int32_t plen;                                           // payload length
+       int32_t rmr_ver;                                        // our internal message version number
+       unsigned char xid[32];                          // space for user transaction id or somesuch
+       unsigned char sid[32];                          // sender ID for return to sender needs
+       unsigned char src[64];                          // name of the sender (source)
+       unsigned char meid[32];                         // 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 stuff
+       unsigned char srcip[64];                        // sender ID for return to sender needs
+};
+
+// --  emulation control functions ------------------------------------------------------
+
+/*
+       Test app can call this to have all emulated functions return failure instead
+       of success.
+*/
+static void en_set_return( int rv ) {
+       return_value = rv;
+}
+
+static int em_nng_foo() {
+       fprintf( stderr, "emulated functions in play" );
+}
+
+/*
+       Turns on/off the generation of multi-threaded call messages
+*/
+static int em_set_mtc_msgs( int state ) {
+       em_mtc_msgs = state;
+}
+
+/*
+       Returns the size of the header we inserted
+*/
+static int em_hdr_size() {
+       if( em_mtc_msgs ) {
+               return (int) sizeof( struct em_msg ) + 4;
+       }
+
+       return (int) sizeof( struct em_msg );
+}
+
+static void em_set_rcvcount( int v ) {
+       rcv_count = v;
+}
+
+static void em_set_rcvdelay( int v ) {
+       if( v < 0 ) {
+               fprintf( stderr, "<EM>   ##ERR## attempt to set receive delay with invalid value was ignored: %d seconds\n", v );
+               return;
+       }
+       fprintf( stderr, "<EM>   receive delay is now %d seconds\n", v );
+       rcv_delay = v;
+}
+
+static void em_start() {
+       if( ! gates_ok ) {
+               pthread_mutex_init( &rcv_gate, NULL );
+               gates_ok = 1;
+       }
+}
+
+
+// ----------- gethostname emulation ---------------------------------------
+#define gethostname  em_gethostname
+static int em_gethostname( char* buf, size_t len ) {
+       if( len < 1 ) {
+               errno = EINVAL;
+               return 1;
+       }
+
+       if( em_gen_long_hostname ) {
+               snprintf( buf, len, "hostname-which-is-long-a860430b890219-dfw82" );
+       } else {
+               snprintf( buf, len, "em-hostname" );
+       }
+
+       return 0;
+}
+
+static int em_set_long_hostname( int v ) {
+       em_gen_long_hostname = !!v;
+}
+
+
+// ----------- epoll emulation ---------------------------------------------
+
+// CAUTION: sys/epoll.h must be included before these define for functions 
+//                     to properly compile.
+//
+#include <sys/epoll.h>
+#define epoll_wait em_wait
+#define epoll_ctl  em_ep_ctl
+#define epoll_create  em_ep_create
+
+/*
+       Every other call returns 1 ready; alternate calls return 0 ready.
+       Mostly for testing the timeout receive call. First call should return
+       something ready and the second should return nothing ready so we can
+       drive both cases.
+*/
+static int em_wait( int fd, void* events, int n, int to ) {
+       static int ready = 0;
+
+       ready = !ready;
+       return ready;
+}
+
+static int em_ep_ctl( int epfd, int op, int fd, struct epoll_event *event ) {
+       return 0;
+}
+
+static int em_ep_create( int size ) {
+       return 0;
+}
+
+
+
+#endif
diff --git a/test/test_ctx_support.c b/test/test_ctx_support.c
new file mode 100644 (file)
index 0000000..277f741
--- /dev/null
@@ -0,0 +1,76 @@
+// : vi ts=4 sw=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.
+==================================================================================
+*/
+
+/*
+       Mnemonic:       test_ctx_support.c
+       Abstract:       This is some support for defining dummy contex struct as
+                               they may need to contian rings and the like for successful
+                               testing, and it may be too much to call rmr_init() to generate
+                               one without dragging the whole test under.
+
+       Author:         E. Scott Daniels
+       Date:           21 February 2020
+*/
+
+#ifndef _test_ctx_support_c
+#define _test_ctx_support_c
+
+#ifdef NNG_UNDER_TEST                                                  // add in the nng only things
+
+#include <rmr_nng_private.h>                   // nng specific context
+
+static inline uta_ctx_t *mk_dummy_ctx() {
+       uta_ctx_t*      ctx;
+
+       ctx = (uta_ctx_t *) malloc( sizeof( *ctx ) );
+       if( ctx == NULL ) {
+               return NULL;
+       }
+
+       memset( ctx, 0, sizeof( *ctx ) );
+
+       return ctx;
+}
+
+#else                                                                                  // assume si is under test
+
+#include <rmr_si_private.h>                                            // si specific context
+#include <ring_static.c>
+
+static inline uta_ctx_t *mk_dummy_ctx() {
+       uta_ctx_t*      ctx;
+
+       ctx = (uta_ctx_t *) malloc( sizeof( *ctx ) );
+       if( ctx == NULL ) {
+               return NULL;
+       }
+
+       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 );
+
+       return ctx;
+}
+
+#endif
+
+#endif
index fc60301..c2c1e80 100644 (file)
 #define _em_nn
 
 #include <pthread.h>
-
-static int em_send_failures = 0;       // test programme can set this to emulate eagain send failures
-static int em_timeout = -1;                    // set by set socket option
-static int em_mtc_msgs = 0;                    // set to generate 'received' messages with mt-call header data
-static int return_value = 0;           // functions should return this value
-static int rcv_count = 0;                      // receive counter for transaction id to allow test to rest
-static int rcv_delay = 0;                      // forced delay before call to rcvmsg starts to work
-
-static int gates_ok = 0;
-static pthread_mutex_t rcv_gate;
-static int em_gen_long_hostname = 0;           // if set the emulated hostname generates a longer name (>40 char)
-
-
-// ----------- gethostname emulation ---------------------------------------
-#define gethostname  em_gethostname
-static int em_gethostname( char* buf, size_t len ) {
-       if( len < 1 ) {
-               errno = EINVAL;
-               return 1;
-       }
-
-       if( em_gen_long_hostname ) {
-               snprintf( buf, len, "hostname-which-is-long-a860430b890219-dfw82" );
-       } else {
-               snprintf( buf, len, "em-hostname" );
-       }
-
-       return 0;
-}
-
-static int em_set_long_hostname( int v ) {
-       em_gen_long_hostname = !!v;
-}
-
-// ----------- epoll emulation ---------------------------------------------
-
-// CAUTION: sys/epoll.h must be included before these define and function will properly compile.
-#define epoll_wait em_wait
-#define epoll_ctl  em_ep_ctl
-#define epoll_create  em_ep_create
-
-/*
-       Every other call returns 1 ready; alternate calls return 0 ready.
-       Mostly for testing the timeout receive call. First call should return
-       something ready and the second should return nothing ready so we can
-       drive both cases.
-*/
-static int em_wait( int fd, void* events, int n, int to ) {
-       static int ready = 0;
-
-       ready = !ready;
-       return ready;
-}
-
-int em_ep_ctl( int epfd, int op, int fd, struct epoll_event *event ) {
-       return 0;
-}
-
-int em_ep_create( int size ) {
-       return 0;
-}
-
-
-
-/*
-       Simulated v1 message for receive to return. This needs to match the RMr header
-       so that we can fill in length, type and xaction id things.
-#define MSG_VER 1
-struct em_msg {
-       int32_t mtype;                                          // message type  ("long" network integer)
-       int32_t plen;                                           // payload length
-       int32_t rmr_ver;                                        // our internal message version number
-       unsigned char xid[32];                          // space for user transaction id or somesuch
-       unsigned char sid[32];                          // sender ID for return to sender needs
-       unsigned char src[16];                          // name of the sender (source)
-       unsigned char meid[32];                         // managed element id.
-       struct timespec ts;                                     // timestamp ???
-};
-*/
-
-/*
-       v2 message; should be able to use it for everything that is set up here as
-       we don't add a payload even if setting a v1 type.
-*/
-#define ALT_MSG_VER 1  // alternate every so often
-#define MSG_VER 3              // default version to insert
-struct em_msg {
-       int32_t mtype;                                          // message type  ("long" network integer)
-       int32_t plen;                                           // payload length
-       int32_t rmr_ver;                                        // our internal message version number
-       unsigned char xid[32];                          // space for user transaction id or somesuch
-       unsigned char sid[32];                          // sender ID for return to sender needs
-       unsigned char src[64];                          // name of the sender (source)
-       unsigned char meid[32];                         // 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 stuff
-       unsigned char srcip[64];                                // sender ID for return to sender needs
-};
-
-
-
-// --  emulation control functions ------------------------------------------------------
-
-/*
-       Test app can call this to have all emulated functions return failure instead
-       of success.
-*/
-static void en_set_return( int rv ) {
-       return_value = rv;
-}
-
-
-
-static int em_nng_foo() {
-       fprintf( stderr, "emulated functions in play" );
-}
-
-
-/*
-       Turns on/off the generation of multi-threaded call messages
-*/
-static int em_set_mtc_msgs( int state ) {
-       em_mtc_msgs = state;
-}
-
-/*
-       Returns the size of the header we inserted
-*/
-static int em_hdr_size() {
-       if( em_mtc_msgs ) {
-               return (int) sizeof( struct em_msg ) + 4;
-       }
-
-       return (int) sizeof( struct em_msg );
-}
-
-static void em_set_rcvcount( int v ) {
-       rcv_count = v;
-}
-
-static void em_set_rcvdelay( int v ) {
-       if( v < 0 ) {
-               fprintf( stderr, "<EM>   ##ERR## attempt to set receive delay with invalid value was ignored: %d seconds\n", v );
-               return;
-       }
-       fprintf( stderr, "<EM>   receive delay is now %d seconds\n", v );
-       rcv_delay = v;
-}
-
-static void em_start() {
-       if( ! gates_ok ) {
-               pthread_mutex_init( &rcv_gate, NULL );
-               gates_ok = 1;
-       }
-}
+#include "test_common_em.c"                    // things common to all emulation code
 
 //--------------------------------------------------------------------------
 #ifdef EMULATE_NNG
@@ -211,6 +48,7 @@ struct nn_msghdr {
        int boo;
 };
 
+#define SOCKET_TYPE            nng_socket              // socket representation is different in each transport
 
 /*
        Receive message must allocate a new buffer and return the pointer into *m.
@@ -448,6 +286,8 @@ static int em_nng_getopt_int( nng_socket s, void* con, int* target ) {
 
 #else
 
+#define SOCKET_TYPE            int             // socket representation is different in each transport
+
 
 // ----------------------- emulated nano functions --------------------------
 struct em_nn_msghdr {
diff --git a/test/test_si95_em.c b/test/test_si95_em.c
new file mode 100644 (file)
index 0000000..6dc33cc
--- /dev/null
@@ -0,0 +1,313 @@
+/*
+==================================================================================
+       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.
+==================================================================================
+*/
+
+/*
+       Mnemonic:       test_si95_em.c
+       Abstract:       This supplies a bunch of dummy SI95 functions which emulate
+                               the sending/receiving of data such that modules can be tested
+                               without the acutal backing of a network.
+
+                               This module must be directly included to be used.
+       Date:           20 February 2020
+       Author:         E. Scott Daniels
+*/
+
+
+#include "rmr.h"                               // we use some of rmr defs in building dummy messages, so we need these
+#include "rmr_agnostic.h"
+
+// ---------------------- emulated nng functions ---------------------------
+
+
+#ifndef _em_si         // this is the same define as the nng emulation code uses to give warning if both included
+#define _em_si
+
+#include <arpa/inet.h>
+#include <pthread.h>
+
+#include "test_common_em.c"                    // common emulation needed for all (epoll, gethostname...)
+
+//--------------------------------------------------------------------------
+/*
+       These are the current references in the RMR code; all others are internal
+       to the SI portion of the library
+
+       SIcbreg( ctx->si_ctx, 
+       SIwait( ctx->si_ctx );
+       SIinitialise( SI_OPT_FG );              // FIX ME: si needs to streamline and drop fork/bg stuff
+       SIlistener( ctx->si_ctx, TCP_DEVICE, bind_info )) < 0 ) {
+       SItp_stats( ctx->si_ctx );                      // dump some interesting stats
+       SIclose( ctx->nn_sock );
+       SIset_tflags( ctx->si_ctx, SI_TF_FASTACK );
+       SIconnect( si_ctx, conn_info )) < 0 ) {
+       SIsendt( ctx->si_ctx, nn_sock, msg->tp_buf, tot_len )) != SI_OK ) {
+*/
+
+#define SIEM_BLOCKED   18
+#define SIEM_ERROR             (-1)
+#define SIEM_OK                        0
+
+#define SOCKET_TYPE            int             // socket representation is different in each transport
+
+struct ginfo_blk;                              // defined in SI things, but must exist here
+
+#include "si95/socket_if.h"            // need to have the si context more than anything else
+
+
+static void *em_sinew( int type ) {
+       return NULL;
+}
+
+static char *em_sigetname( int sid ) {
+       return "somename";
+}
+
+static int em_siaddress( void *src, void **dest, int type ) {
+       return 0;
+}
+
+static void em_sibldpoll( struct ginfo_blk* gptr ) {
+       return;
+}
+
+static struct tp_blk *em_siconn_prep( struct ginfo_blk *gptr, int type, char *abuf, int family ) {
+       return NULL;
+}
+
+/*
+       Caller passing a callback funciton for SI to drive; nothing to do.
+*/
+void *em_cb_data = NULL;
+static void em_sicbreg( struct ginfo_blk *gptr, int type, int ((*fptr)()), void * dptr ) {
+       if( em_cb_data == NULL ) {
+               fprintf( stderr, "<SIEM> calldback dptr saved for type %d\n", type );
+               em_cb_data = dptr;
+       }
+       return;
+}
+
+static void em_sicbstat( struct ginfo_blk *gptr, int status, int type ) {
+       return;
+}
+
+static int em_siclose( struct ginfo_blk *gptr, int fd ) {
+       return 0;
+}
+
+/*
+       If em_send_failures is true, this will fail a small part of the time
+       to simualte connection failures.
+*/
+static int em_next_fd = 0;
+static int em_siconnect( struct ginfo_blk *gptr, char *abuf ) {
+       static int count = 0;
+
+       if( em_send_failures && (count++ % 15 == 14) ) {
+               //fprintf( stderr, "<SIEM> siem is failing connect attempt\n\n" );
+               return -1;
+       }
+
+       fprintf( stderr, "<SIEM> siem is emulating connect attempt return fd=%d\n", em_next_fd );
+       em_next_fd++;
+       return em_next_fd-1;
+}
+
+static struct tp_blk *em_siestablish( int type, char *abuf, int family ) {
+       return NULL;
+}
+
+static int em_sigenaddr( char *target, int proto, int family, int socktype, struct sockaddr **rap ) {
+       return 0;
+}
+
+static int em_sigetaddr( struct ginfo_blk *gptr, char *buf ) {
+       return 0;
+}
+
+static struct tp_blk *em_silisten_prep( struct ginfo_blk *gptr, int type, char* abuf, int family ) {
+       return NULL;
+}
+
+/*
+       Called to open a listen port; returns the port fd or -1 on error.
+*/
+static int em_silistener( struct ginfo_blk *gptr, int type, char *abuf ) {
+       return 100;
+}
+
+static void em_simap_fd( struct ginfo_blk *gptr, int fd, struct tp_blk* tpptr ) {
+       return;
+}
+
+static int em_sinewsession( struct ginfo_blk *gptr, struct tp_blk *tpptr ) {
+       return 0;
+}
+
+static int em_sipoll( struct ginfo_blk *gptr, int msdelay ) {
+       return 0;
+}
+
+static int em_sircv( struct ginfo_blk *gptr, int sid, char *buf, int buflen, char *abuf, int delay ) {
+       return 0;
+}
+
+static void em_sisend( struct ginfo_blk *gptr, struct tp_blk *tpptr ) {
+       return;
+}
+
+//  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
+       of the code in RMr.
+
+       "Send a message" by passing it to the callback if we have a non-nil cb data pointer.
+       We'll divide the data into two to test the concatination of the receiver.
+*/
+static int em_sisendt( struct ginfo_blk *gptr, int fd, char *ubuf, int ulen ) {
+       static int count = 0;
+       static int uss = -1;            // ultra short send done
+
+       if( em_send_failures && ((count++ % 15) == 14) ) {
+               //fprintf( stderr, "<SIEM> sendt is failing send with blocked/again\n\n" );
+               errno = EAGAIN;
+               return SIEM_BLOCKED;
+       }
+
+       uss++;
+
+       if( em_cb_data != NULL ) {
+               if( uss == 1 ) {                                        // drive the reconstruction where a split in the msg length happens
+                       fprintf( stderr, "<SIEM> sendt is queuing ultra short first packet of a two packet sendh len=%d\n", ulen );
+                       mt_data_cb( em_cb_data, 0, ubuf, 3 );
+                       mt_data_cb( em_cb_data, 0, ubuf+3, ulen - 3 );
+               } else {
+                       if( ulen > 100 ) {
+                               fprintf( stderr, "<SIEM> sendt is queuing two packets with the callback len=%d\n", ulen );
+                               mt_data_cb( em_cb_data, 0, ubuf, 100 );
+                               mt_data_cb( em_cb_data, 0, ubuf+100, ulen - 100 );
+                       } else {
+                               fprintf( stderr, "<SIEM> sendt is queuing one packet with the callback len=%d\n", ulen );
+                               mt_data_cb( em_cb_data, 0, ubuf, ulen );
+                       }
+               }
+       }
+
+       errno = 0;
+       //fprintf( stderr, "<SIEM> sendt is returning default reeturn status: %d\n", return_value );
+       return return_value;
+}
+
+/*
+       Sets flags; ignore.
+*/
+static void em_siset_tflags( struct ginfo_blk *gp, int flags ) {
+       return;
+}
+
+static int em_sishow_version( ) {
+       return 0;
+}
+
+static void em_sishutdown( struct ginfo_blk *gptr ) {
+       return;
+}
+
+/*
+       This prints some SI stats -- ignore.
+*/
+static void em_sitp_stats( void *vgp ) {
+       return;
+}
+
+static void em_siterm( struct ginfo_blk* gptr, struct tp_blk *tpptr ) {
+       return;
+}
+
+static void em_sitrash( int type, void *bp ) {
+       return;
+}
+
+/*
+       This will be tricky.  Wait receives raw packets from the network
+       and drives the callback(s) which are registered.  We'll need to 
+       simulate driving the callback with data that spans multiple FDs
+       and has messages split across buffers, but does not block foreaver
+       so the test can continue.
+       It won't be pretty.
+
+       For now We'll hard code the RMR callback functions and not 
+       try to use what it passes via the register function lest we
+       need to implement all of SI just to run unit tests.
+
+
+       Thinking: use rmr's alloc function to alloc a message buffer
+       which we fill in.  We can cheat and add the length as RMR does
+       on send, and then split the buffer as we feed it back to the 
+       callback function.
+*/
+static int em_siwait( struct ginfo_blk *gptr ) {
+       return 0;
+}
+
+/*
+       The emulation doesn't use the global info stuff, so alloc something
+       to generate a pointer.
+*/
+static struct ginfo_blk *em_siinitialise( int opts ) {
+       void *p;
+
+       p = malloc( 1024 );
+       return p;
+}
+
+
+// redefine all SI calls to reference functions here.
+#define SInew em_sinew
+#define sigetname em_sigetname
+#define SIaddress em_siaddress
+#define SIbldpoll em_sibldpoll
+#define SIconn_prep em_siconn_prep
+#define SIcbreg em_sicbreg
+#define SIcbstat em_sicbstat
+//#define SIclose em_siclose
+#define SIconnect em_siconnect
+#define SIestablish em_siestablish
+#define SIgenaddr em_sigenaddr
+#define SIgetaddr em_sigetaddr
+#define SIlisten_prep em_silisten_prep
+#define SIlistener em_silistener
+#define SImap_fd em_simap_fd
+#define SInewsession em_sinewsession
+#define SIpoll em_sipoll
+#define SIrcv em_sircv
+#define SIsend em_sisend
+#define SIsendt em_sisendt
+#define SIset_tflags em_siset_tflags
+#define SIshow_version em_sishow_version
+#define SIshutdown em_sishutdown
+#define SItp_stats em_sitp_stats
+#define SIterm em_siterm
+#define SItrash em_sitrash
+#define SIwait em_siwait
+#define SIinitialise em_siinitialise
+
+
+#endif
index 084256f..8429e50 100644 (file)
@@ -1,8 +1,8 @@
 // : vi ts=4 sw=4 noet :
 /*
 ==================================================================================
-           Copyright (c) 2019 Nokia
-           Copyright (c) 2018-2019 AT&T Intellectual Property.
+           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.
 #include <fcntl.h>
 #include <unistd.h>
 
+/*
+       This is ugly, but needed to allow for component testing.
+
+       The test code (e.g. foo_test.c and not foo_static_test.c) can include these
+       constants to turn off the import of test support files:
+               NO_EMULATION            -- the transport emulation will not be included
+               NO_PRIVATE_HEADERS      -- the private headers for the transport component of RMR
+                                                               (e.g. si) will not be included.
+*/
+#ifndef NO_EMULATION                           // assume emulation unless specifically put off (love double negatives)
+       #ifdef NNG_UNDER_TEST
+               #define TP_HDR_LEN 0                            // needed for support functions but nonexistant in nng world
+               #include "test_nng_em.c"                        // nano/ngg emulation functions
+       #else
+               #include "test_si95_em.c"                       // si emulation functions
+       #endif
+#endif
+
+#ifndef NO_PRIVATE_HEADERS                                     // include transport headers unless specifically turned off
+       #ifdef NNG_UNDER_TEST
+               #include <rmr_nng_private.h>            // context things are type sensitive
+       #else
+               #include "si95/socket_if.h"                     // need to have the si context more than anything else
+               #include <rmr_si_private.h>
+       #endif
+#endif
+
 #ifndef BAD
 #define BAD 1                  // these are exit codes unless user overrides
 #define GOOD 0
@@ -167,7 +194,7 @@ static rmr_mbuf_t* test_mk_msg( int len, int tr_len ) {
        uta_mhdr_t* hdr;
        size_t  alen;
 
-       alen = sizeof( *hdr ) + tr_len + len;   // this does no support allocating len2 and len3 data fields
+       alen = sizeof( *hdr ) + tr_len + len + TP_HDR_LEN;      // this does no support allocating len2 and len3 data fields
 
        new_msg = (rmr_mbuf_t *) malloc( sizeof *new_msg );
        new_msg->tp_buf = (void *) malloc( alen );
index 64da983..0269522 100644 (file)
@@ -139,20 +139,7 @@ static int tools_test( ) {
        i = uta_lookup_rtg( &ctx );
        errors += fail_if_true( i, "rtg lookup returned that it found something when not expected to" );
 
-/*
-//==== moved out of generic tools ==========
-       // -------------- test link2 stuff ----------------------------------------------------------
-       i = uta_link2( "bad" );                                 // should fail
-       errors += fail_if_true( i >= 0, "uta_link2 didn't fail when given bad address" );
-
-       i = uta_link2( "nohost:-1234" );
-       errors += fail_if_true( i >= 0, "uta_link2 did not failed when given a bad (negative) port " );
-
-       i = uta_link2( "nohost:1234" );                                 // nn should go off and set things up, but it will never successd, but uta_ call should
-       errors += fail_if_true( i < 0, "uta_link2 failed when not expected to" );
-*/
-
-       // ------------ my ip stuff -----------------------------------------------------------------
+       // ------------ my_ip stuff -----------------------------------------------------------------
 
        if_list = mk_ip_list( "1235" );
        errors += fail_if_nil( if_list, "mk_ip_list returned nil pointer" );
index 35aa62f..3a09d44 100644 (file)
@@ -20,7 +20,7 @@
 
 
 /*
-       Mnemonic:       tools_testh.c
+       Mnemonic:       tools_test.c
        Abstract:       Unit tests for the RMr tools module.
        Author:         E. Scott Daniels
        Date:           21 January 2019
 #include "rmr.h"
 #include "rmr_logging.h"
 #include "rmr_agnostic.h"
-#include "test_support.c"              // our private library of test tools
-
-// ===== dummy context for tools testing so we don't have to pull in all of the nano/nng specific stuff =====
-struct uta_ctx {
-       char*   my_name;                        // dns name of this host to set in sender field of a message
-       int     shutdown;                               // thread notification if we need to tell them to stop
-       int max_mlen;                           // max message length payload+header
-       int     max_plen;                               // max payload length
-       int     flags;                                  // CTXFL_ constants
-       int nrtele;                                     // number of elements in the routing table
-       int send_retries;                       // number of retries send_msg() should attempt if eagain/timeout indicated by nng
-       //nng_socket    nn_sock;                // our general listen socket
-       route_table_t* rtable;          // the active route table
-       route_table_t* old_rtable;      // the previously used rt, sits here to allow for draining
-       route_table_t* new_rtable;      // route table under construction
-       if_addrs_t*     ip_list;                // list manager of the IP addresses that are on our known interfaces
-       void*   mring;                          // ring where msgs are queued while waiting for a call response msg
-
-       char*   rtg_addr;                       // addr/port of the route table generation publisher
-       int             rtg_port;                       // the port that the rtg listens on
-
-       wh_mgt_t*       wormholes;              // management of user opened wormholes
-       //epoll_stuff_t*        eps;            // epoll information needed for the rcv with timeout call
-
-       //pthread_t     rtc_th;                 // thread info for the rtc listener
-};
 
+#define NO_EMULATION
+#include "test_support.c"              // our private library of test tools
 
 #include "tools_static.c"
 
index 35e3383..80712a5 100755 (executable)
@@ -1,5 +1,5 @@
 #!/usr/bin/env ksh
-# this will fail if run with bash!
+# this has been hacked to work with bash; ksh is preferred
 
 #==================================================================================
 #        Copyright (c) 2019 Nokia
 # -------------------------------------------------------------------------
 
 function usage {
-       echo "usage: $0 [-G|-M|-C custom-command-string] [-c cov-target]  [-f] [-F] [-v] [-x]  [files]"
+       echo "usage: $0 [-G|-M|-C custom-command-string] [-a] [-c cov-target]  [-f] [-F] [-v] [-x]  [files]"
        echo "  if -C is used to provide a custom build command then it must "
        echo "  contain a %s which will be replaced with the unit test file name."
        echo '  e.g.:  -C "mk -a %s"'
+       echo "  -a always run coverage (even on failed modules)"
        echo "  -c allows user to set the target coverage for a module to pass; default is 80"
        echo "  -f forces a discount check (normally done only if coverage < target)"
        echo "  -F show only failures at the function level"
@@ -81,19 +82,25 @@ function usage {
 function add_ignored_func {
        if [[ ! -r $1 ]]
        then
+               echo ">>>> can't find file to ignore: $1" 
                return
        fi
 
        typeset f=""
-       grep "^static.*(.*).*{" $1 | awk '              # get list of test functions to ignore
-               {
-                       gsub( "[(].*", "" )
-                       print $3
-               }
-       ' | while read f
-       do
-               iflist="${iflist}$f "
-       done
+       goop=$(
+               grep "^static.*(.*).*{" $1 | awk '              # get list of test functions to ignore
+                       {
+                               gsub( "[(].*", "" )
+                               gsub( "[*]", "" )
+                               if( $2 == "struct" ) {                  # static struct goober function
+                                       printf( "%s ", $4 )
+                               } else {
+                                       printf( "%s ", $3 )                     # static goober-type funct
+                               }
+                       }
+               ' )
+
+       iflist="$iflist $goop"                  # this goop hack because bash can't read from a loop
 }
 
 
@@ -285,7 +292,8 @@ function get_mct {
 
        if [[ -f ./.targets ]]
        then
-               grep "^$1 " ./.targets | head -1 | read junk tv
+               grep "^$1 " ./.targets | head -1 | read stuff
+               tv="${stuff##* }"                                       # assume junk tv; ditch junk
        fi
 
        echo ${tv:-$v}
@@ -323,20 +331,24 @@ fi
 
 export LIBRARY_PATH=$LD_LIBRARY_PATH
 
-export C_INCLUDE_PATH="../src/rmr/common/include:$C_INCLUDE_PATH"
+# The Makefile sets specific includes for things
+#export C_INCLUDE_PATH="../src/rmr/common/include:../src/rmr/si/include:$C_INCLUDE_PATH"
 
 module_cov_target=80
-builder="make -B %s"           # default to plain ole make
+builder="make -B %s"                                                   # default to plain ole make
 verbose=0
-show_all=1                                     # show all things -F sets to show failures only
-strict=0                                       # -s (strict) will set; when off, coverage state ignored in final pass/fail
-show_output=0                          # show output from each test execution (-S)
+show_all=1                                                                             # show all things -F sets to show failures only
+strict=0                                                                               # -s (strict) will set; when off, coverage state ignored in final pass/fail
+show_output=0                                                                  # show output from each test execution (-S)
 quiet=0
 gen_xml=0
-replace_flags=1                                # replace ##### in gcov for discounted lines
+replace_flags=1                                                                        # replace ##### in gcov for discounted lines
 run_nano_tests=0
+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
 
-export RMR_WARNING=1           # turn on warnings
+export RMR_WARNING=1                                                   # turn on warnings
 
 ulimit -c unlimited
 
@@ -347,7 +359,9 @@ do
                -G)     builder="gmake %s";;
                -M)     builder="mk -a %s";;            # use plan-9 mk (better, but sadly not widly used)
                -N)     run_nano_tests=1;;
+               -O)     out_dir=$2; shift;;
 
+               -a)     always_gcov=1;;
                -c)     module_cov_target=$2; shift;;
                -e)     capture_file=$2; >$capture_file; shift;;                # capture errors from failed tests rather than spewing on tty
                -f)     force_discounting=1;
@@ -356,6 +370,8 @@ do
 
                -F)     show_all=0;;
 
+               -n)     noexec=1;;
+               -o)     save_gcov=0;;
                -s)     strict=1;;                                      # coverage counts toward pass/fail state
                -S)     show_output=1;;                         # test output shown even on success
                -v)     (( verbose++ ));;
@@ -366,6 +382,7 @@ do
                        rm -fr *cov.xml
                        ;;
 
+
                -h)     usage; exit 0;;
                --help) usage; exit 0;;
                -\?)    usage; exit 0;;
@@ -412,6 +429,16 @@ else
 fi
 
 
+if (( noexec ))
+then
+       echo "no exec mode; would test these:"
+       for tf in $flist
+       do
+               echo "  $tf"
+       done
+       exit 0
+fi
+
 rm -fr *.gcov                  # ditch the previous coverage files
 ut_errors=0                    # unit test errors (not coverage errors)
 errors=0
@@ -426,192 +453,205 @@ do
                fi
        done
 
-       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$$
-               exit 1
-       fi
-
-       iflist="main sig_clean_exit "           # ignore external functions from our tools
-       add_ignored_func $tfile                         # ignore all static functions in our test driver
-       add_ignored_func test_support.c         # ignore all static functions in our test tools
-       add_ignored_func test_nng_em.c          # the nng/nano emulated things
-       for f in *_static_test.c                        # all static modules here
-       do
-               if(( ! run_nano_tests )) && [[ $f == *"nano"* ]]
+       (       # 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
-                       continue
+                       echo "[FAIL] cannot build $tfile"
+                       cat /tmp/PID$$.log
+                       rm -f /tmp/PID$$
+                       exit 1
                fi
 
-               add_ignored_func $f
-       done
+               iflist="main sig_clean_exit "           # ignore external functions from our tools
+               add_ignored_func $tfile                         # ignore all static functions in our test driver
+               add_ignored_func test_support.c         # ignore all static functions in our test tools
+               add_ignored_func test_nng_em.c          # the nng/nano emulated things
+               add_ignored_func test_si95_em.c         # the si emulated things
+               add_ignored_func test_common_em.c       # the common emulation functions
+               for f in *_static_test.c                        # all static modules here
+               do
+                       if(( ! run_nano_tests )) && [[ $f == *"nano"* ]]
+                       then
+                               continue
+                       fi
 
-       if ! ./${tfile%.c} >/tmp/PID$$.log 2>&1
-       then
-               echo "[FAIL] unit test failed for: $tfile"
-               if [[ -n $capture_file ]] 
+                       add_ignored_func $f
+               done
+
+               if ! ./${tfile%.c} >/tmp/PID$$.log 2>&1
                then
-                       echo "all errors captured in $capture_file, listing only fail message on tty"
-                       echo "$tfile --------------------------------------" >>$capture_file
-                       cat /tmp/PID$$.log >>$capture_file
-                       grep "^<FAIL>" /tmp/PID$$.log
-                       echo ""
-               else
-                       if (( quiet ))
+                       echo "[FAIL] unit test failed for: $tfile"
+                       if [[ -n $capture_file ]] 
                        then
-                               grep "^<" /tmp/PID$$.log|grep -v "^<EM>"        # in quiet mode just dump <...> messages which are assumed from the test programme not appl
+                               echo "all errors captured in $capture_file, listing only fail message on tty"
+                               echo "$tfile --------------------------------------" >>$capture_file
+                               cat /tmp/PID$$.log >>$capture_file
+                               grep "^<FAIL>" /tmp/PID$$.log
+                               echo ""
                        else
+                               if (( quiet ))
+                               then
+                                       grep "^<" /tmp/PID$$.log|grep -v "^<EM>"        # in quiet mode just dump <...> messages which are assumed from the test programme not appl
+                               else
+                                       cat /tmp/PID$$.log
+                               fi
+                       fi
+                       (( ut_errors++ ))                               # cause failure even if not in strict mode
+                       if (( ! always_gcov ))
+                       then
+                               continue                                                # skip coverage tests for this
+                       fi
+               else
+                       if (( show_output ))
+                       then
+                               printf "\n============= test programme output =======================\n"
                                cat /tmp/PID$$.log
+                               printf "===========================================================\n"
                        fi
                fi
-               (( ut_errors++ ))                               # cause failure even if not in strict mode
-               continue                                                # skip coverage tests for this
-       else
-               if (( show_output ))
-               then
-                       printf "\n============= test programme output =======================\n"
-                       cat /tmp/PID$$.log
-                       printf "===========================================================\n"
-               fi
-       fi
-
-       (
-               touch ./.targets
-               sed '/^#/ d; /^$/ d; s/^/TARGET: /' ./.targets
-               gcov -f ${tfile%.c} | sed "s/'//g"
-       ) | awk \
-               -v cfail=$cfail \
-               -v show_all=$show_all \
-               -v ignore_list="$iflist" \
-               -v module_cov_target=$module_cov_target \
-               -v chatty=$verbose \
-               '
-               BEGIN {
-                       announce_target = 1;
-                       nignore = split( ignore_list, ignore, " " )
-                       for( i = 1; i <= nignore; i++ ) {
-                               imap[ignore[i]] = 1
-                       }
 
-                       exit_code = 0           # assume good
-               }
+               (
+                       touch ./.targets
+                       sed '/^#/ d; /^$/ d; s/^/TARGET: /' ./.targets
+                       gcov -f ${tfile%.c} | sed "s/'//g"
+               ) | awk \
+                       -v cfail=$cfail \
+                       -v show_all=$show_all \
+                       -v ignore_list="$iflist" \
+                       -v module_cov_target=$module_cov_target \
+                       -v chatty=$verbose \
+                       '
+                       BEGIN {
+                               announce_target = 1;
+                               nignore = split( ignore_list, ignore, " " )
+                               for( i = 1; i <= nignore; i++ ) {
+                                       imap[ignore[i]] = 1
+                               }
 
-               /^TARGET:/ {
-                       if( NF > 1 ) {
-                               target[$2] = $NF
+                               exit_code = 0           # assume good
                        }
-                       next;
-               }
-
-               /File.*_test/ || /File.*test_/ {                # dont report on test files
-                       skip = 1
-                       file = 1
-                       fname = $2
-                       next
-               }
 
-               /File/ {
-                       skip = 0
-                       file = 1
-                       fname = $2
-                       next
-               }
+                       /^TARGET:/ {
+                               if( NF > 1 ) {
+                                       target[$2] = $NF
+                               }
+                               next;
+                       }
 
-               /Function/ {
-                       fname = $2
-                       file = 0
-                       if( imap[fname] ) {
-                               fname = "skipped: " fname               # should never see and make it smell if we do
+                       /File.*_test/ || /File.*test_/ {                # dont report on test files
                                skip = 1
-                       } else {
+                               file = 1
+                               fname = $2
+                               next
+                       }
+
+                       /File/ {
                                skip = 0
+                               file = 1
+                               fname = $2
+                               next
                        }
-                       next
-               }
 
-               skip { next }
+                       /Function/ {
+                               fname = $2
+                               file = 0
+                               if( imap[fname] ) {
+                                       fname = "skipped: " fname               # should never see and make it smell if we do
+                                       skip = 1
+                               } else {
+                                       skip = 0
+                               }
+                               next
+                       }
 
-               /Lines executed/ {
-                       split( $0, a, ":" )
-                       pct = a[2]+0
+                       skip { next }
 
-                       if( file ) {
-                               if( announce_target ) {                         # announce default once at start
-                                       announce_target = 0;
-                                       printf( "\n[INFO] default target coverage for modules is %d%%\n", module_cov_target )
-                               }
+                       /Lines executed/ {
+                               split( $0, a, ":" )
+                               pct = a[2]+0
 
-                               if( target[fname] ) {
-                                       mct = target[fname]
-                                       announce_target = 1;
-                               } else {
-                                       mct = module_cov_target
-                               }
+                               if( file ) {
+                                       if( announce_target ) {                         # announce default once at start
+                                               announce_target = 0;
+                                               printf( "\n[INFO] default target coverage for modules is %d%%\n", module_cov_target )
+                                       }
 
-                               if( announce_target ) {                                 # annoucne for module if different from default
-                                       printf( "[INFO] target coverage for %s is %d%%\n", fname, mct )
-                               }
+                                       if( target[fname] ) {
+                                               mct = target[fname]
+                                               announce_target = 1;
+                                       } else {
+                                               mct = module_cov_target
+                                       }
 
-                               if( pct < mct ) {
-                                       printf( "[%s] %3d%% %s\n", cfail, pct, fname )  # CAUTION: write only 3 things  here
-                                       exit_code = 1
-                               } else {
-                                       printf( "[PASS] %3d%% %s\n", pct, fname )
-                               }
+                                       if( announce_target ) {                                 # annoucne for module if different from default
+                                               printf( "[INFO] target coverage for %s is %d%%\n", fname, mct )
+                                       }
 
-                               announce_target = 0;
-                       } else {
-                               if( pct < 70 ) {
-                                       printf( "[LOW]  %3d%% %s\n", pct, fname )
+                                       if( pct < mct ) {
+                                               printf( "[%s] %3d%% %s\n", cfail, pct, fname )  # CAUTION: write only 3 things  here
+                                               exit_code = 1
+                                       } else {
+                                               printf( "[PASS] %3d%% %s\n", pct, fname )
+                                       }
+
+                                       announce_target = 0;
                                } else {
-                                       if( pct < 80 ) {
-                                               printf( "[MARG] %3d%% %s\n", pct, fname )
+                                       if( pct < 70 ) {
+                                               printf( "[LOW]  %3d%% %s\n", pct, fname )
                                        } else {
-                                               if( show_all ) {
-                                                       printf( "[OK]   %3d%% %s\n", pct, fname )
+                                               if( pct < 80 ) {
+                                                       printf( "[MARG] %3d%% %s\n", pct, fname )
+                                               } else {
+                                                       if( show_all ) {
+                                                               printf( "[OK]   %3d%% %s\n", pct, fname )
+                                                       }
                                                }
                                        }
                                }
-                       }
 
-               }
+                       }
 
-               END {
-                       printf( "\n" );
-                       exit( exit_code )
-               }
-       ' >/tmp/PID$$.log                                       # capture output to run discount on failures
-       rc=$?
-       cat /tmp/PID$$.log
+                       END {
+                               printf( "\n" );
+                               exit( exit_code )
+                       }
+               ' >/tmp/PID$$.log                                       # capture output to run discount on failures
+               rc=$?
+               cat /tmp/PID$$.log
 
-       if (( rc  || force_discounting ))       # didn't pass, or forcing, see if discounting helps
-       then
-               if (( ! verbose ))
+               if (( rc  || force_discounting ))       # didn't pass, or forcing, see if discounting helps
                then
-                       echo "[INFO] checking to see if discounting improves coverage for failures listed above"
-               fi
-
-               egrep "$trigger_discount_str"  /tmp/PID$$.log | while read state junk  name
-               do
-                       if ! discount_an_checks $name.gcov >/tmp/PID$$.disc
+                       if (( ! verbose ))
                        then
-                               (( errors++ ))
+                               echo "[INFO] checking to see if discounting improves coverage for failures listed above"
                        fi
 
-                       tail -1 /tmp/PID$$.disc | grep '\['
+                       # preferred, but breaks under bash
+                       #egrep "$trigger_discount_str"  /tmp/PID$$.log | while read state junk  name
+                       egrep "$trigger_discount_str"  /tmp/PID$$.log | while read stuff
+                       do
+                               set stuff                       # this hack required because bash cant read into mult vars
+                               state="$1"
+                               name="$3"
 
-                       if (( verbose > 1 ))                    # updated file was generated, keep here
-                       then
-                               echo "[INFO] discounted coverage info in: ${tfile##*/}.dcov"
-                       fi
+                               if ! discount_an_checks $name.gcov >/tmp/PID$$.disc
+                               then
+                                       (( errors++ ))
+                               fi
 
-                       mv /tmp/PID$$.disc ${name##*/}.dcov
-               done
-       fi
+                               tail -1 /tmp/PID$$.disc | grep '\['
+
+                               if (( verbose > 1 ))                    # updated file was generated, keep here
+                               then
+                                       echo "[INFO] discounted coverage info in: ${tfile##*/}.dcov"
+                               fi
+
+                               mv /tmp/PID$$.disc ${name##*/}.dcov
+                       done
+               fi
+       )>/tmp/PID$$.noise 2>&1
 
        for x in *.gcov                                                 # merge any previous coverage file with this one
        do
@@ -622,7 +662,12 @@ do
                        rm $x-
                fi
        done
-done
+
+       if (( ! quiet ))
+       then
+               cat /tmp/PID$$.noise
+       fi
+done 
 
 echo ""
 echo "[INFO] final discount checks on merged gcov files"
@@ -633,10 +678,38 @@ do
        then
                of=${xx%.gcov}.dcov
                discount_an_checks $xx  >$of
-               tail -1 $of |  grep '\['
+               if [[ -n $of ]]
+               then
+                       tail -1 $of |  grep '\['
+               fi
        fi
 done
 
+if (( save_gcov ))
+then
+       echo ""
+       ok=1
+       if [[ ! -d $outdir ]]
+       then
+               if ! mkdir -p $out_dir
+               then
+                       echo "[WARN] unable to save .gcov files in $out_dir"
+                       ok=0
+               fi
+       fi
+
+       if (( ok ))
+       then
+               rm -fr $out_dir/*
+               echo "[INFO] gcov files saved in $out_dir for push to remote system(s)"
+               cp *.gcov $out_dir/
+               rm -f $out_dir/*_test.c.gcov $out_dir/test_*.c.gcov
+               rm -f ./*_test.c.gcov ./test_*.c.gcov
+       fi
+else
+       echo "[INFO] .gcov files were not saved for remote system"
+fi
+
 state=0                                                # final state
 rm -f /tmp/PID$$.*
 if (( strict ))                                # fail if some coverage failed too
@@ -663,5 +736,6 @@ else
                mk_xml
        fi
 fi
+
 exit $state
 
index 47bd85f..7cabffa 100644 (file)
@@ -56,12 +56,7 @@ static int worm_test( ) {
        int             whid = -1;
        int             last_whid;
 
-       ctx = (uta_ctx_t *) malloc( sizeof( uta_ctx_t ) );
-       if( ctx == NULL ) {
-               fail_if_nil( ctx, "could not allocate dummy context" );
-               return 1;
-       }
-       memset( ctx, 0, sizeof( *ctx ) );
+       ctx = mk_dummy_ctx();
        ctx->my_name = strdup( "tester" );
        ctx->my_ip = strdup( "30.4.19.86:1111" );