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).
# -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" )
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" )
--- /dev/null
+#!/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 $?
+
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 );
+ }
}
}
}
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 {
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 {
}
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;
}
/*
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
--- /dev/null
+#
+#==================================================================================
+# 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()
+
--- /dev/null
+#
+#==================================================================================
+# 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).
--- /dev/null
+// :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
+}
+
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
%:: %.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
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
.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
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
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
-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
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
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
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
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
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
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
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
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
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
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
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
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
-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;;
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
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
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
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
#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"
*/
#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"
*/
+#define NO_EMULATION
+
#include <stdio.h>
#include <stdlib.h>
#include <netdb.h>
Date: 3 April 2019
*/
+#define NO_EMULATION
+
#include <unistd.h>
#include <stdio.h>
#include <stdlib.h>
#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)
#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"
// 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
--- /dev/null
+// : 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;
+}
--- /dev/null
+// :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;
+}
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;
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 ) {
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
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 );
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)" );
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
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;
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" );
}
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 );
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;
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
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
}
--- /dev/null
+#!/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
--- /dev/null
+// : 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;
+}
#include "rmr_symtab.h"
// -- parent must include if needed #include "../src/common/src/symtab.c"
-#include "test_support.c"
#ifndef GOOD
#define GOOD 0
*/
#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
--- /dev/null
+/*
+==================================================================================
+ 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
--- /dev/null
+// : 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
#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
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.
#else
+#define SOCKET_TYPE int // socket representation is different in each transport
+
// ----------------------- emulated nano functions --------------------------
struct em_nn_msghdr {
--- /dev/null
+/*
+==================================================================================
+ 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
// : 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
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 );
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" );
/*
- 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"
#!/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"
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
}
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}
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
-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;
-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++ ));;
rm -fr *cov.xml
;;
+
-h) usage; exit 0;;
--help) usage; exit 0;;
-\?) usage; exit 0;;
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
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
rm $x-
fi
done
-done
+
+ if (( ! quiet ))
+ then
+ cat /tmp/PID$$.noise
+ fi
+done
echo ""
echo "[INFO] final discount checks on merged gcov files"
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
mk_xml
fi
fi
+
exit $state
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" );