*.dcov
*.gcno
*.gcda
+*.xml
+*test
+# :vi ts=4 sw=4 noet:
+#
+#==================================================================================
+# Copyright (c) 2019 Nokia
+# Copyright (c) 2018-2019 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.
+#==================================================================================
+#
CC = gcc
#sa_tests = sa_tools_test.o
%.o:: %.c
- $(CC) -g $< -c
+ $(CC) -g $< -c
%:: %.c
- $(CC) -I ../src/common/src/ -I ../src/common/include -I ../src/nng/include $(coverage_opts) -fPIC -g $< -o $@ $(libs)
+ $(CC) -I ../src/common/src/ -I ../src/common/include -I ../src/nng/include -I ../src/nanomsg/include $(coverage_opts) -fPIC -g $< -o $@ $(libs)
-# catch all
+# catch all
all:
echo "run unit_test.ksh to make and run things here"
-#sa_tools_test.o: sa_tools_test.c
-# $(CC) -I ../src/common/src/ -I ../src/common/include -I $(coverage_opts) ../src/nng/include -fPIC -g $< -c
-
-#.PHONY: sa_tests
-#sa_tests: $(sa_tests)
-
# remove intermediates
clean:
rm -f *.gcov *.gcda *.dcov *.gcno
-# remove anything that can be builts
+# remove anything that can be built
nuke: clean
- rm -f ring_test symtab_test
+ rm -f ring_test symtab_test
and complete set of options available.
+Merging .gcov files
+As some unit test programmes may not be able/designed to cover all
+of a module completely, the script will merge each .gcov prooduced
+with the prior, matching, file after each pass. The result is a
+final .gcov file that shows the coverage of the module over all
+tests. This allows a true coverage value to be determined while
+permitting more simple tests to be used without the requirement of
+each test to cover everything.
+
+
Discounting
The unit test script makes a discount pass on low coverage files in
attempt to discount the coverage rate by ignoring what are considered
=====: 358: return 0;
-: 359: }
+A final discount pass is made on all merged .gcov files after all unit
+tests are finished. This final pass should indicate the true discounted
+coverage
+
Target Coverage
By default, a target coverage of 80% is used. For some modules this may
Module names need to be qualified (e.g. ../src/common/src/foo.c.
+Sonar XML Files
+If the -x option is given on the unit test script, then two XML files
+will be generated for Sonar. These are gcov.xml and dcov.xml and are
+the coverage information as reflected in the merged .gcov files and in
+the .dcov files produced during the final pass. The XML files should
+be uploaded to Sonar only after a complete unit test run is made, otherwise
+the coverage information may be lacking (reflecting only the last test
+executed and not a full complement of tests).
+
-----------------------------------------------------------------------
A note about ksh (A.K.A Korn shell, or kshell)
Ksh is preferred for more complex scripts such as the unit test
--- /dev/null
+#!/usr/bin/env ksh
+
+#==================================================================================
+# Copyright (c) 2019 Nokia
+# Copyright (c) 2018-2019 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: cov2xml.ksh
+# Abstract: Process the coverage file(s) which are read from standard in
+# to generate a single set of XML output that Sonar can ingest.
+# Basic usage is:
+# cat *.gcov | cov2xml.ksh >file.xml
+#
+# The XML generated is based on the Sonar doc:
+# https://docs.sonarqube.org/latest/analysis/generic-test/
+#
+# Date: 30 April 2019
+# Author: E. Scott Daniels
+# -------------------------------------------------------------------------
+
+awk '
+ function start() {
+ printf( "<coverage version=\"1\">\n" ) # sonar is VERY picky about this
+ }
+
+ function end() {
+ printf( "</coverage>\n" )
+ }
+
+ function start_file( name ) {
+ printf( "<file path=\"%s\">\n", name )
+ }
+
+ function end_file( ) {
+ printf( "</file>\n" )
+ }
+
+ function good_line( num ) {
+ if( num > 0 ) {
+ printf( "<lineToCover lineNumber=\"%d\" covered=\"true\"/>\n", num )
+ }
+ }
+
+ function bad_line( num ) {
+ if( num > 0 ) {
+ printf( "<lineToCover lineNumber=\"%d\" covered=\"false\"/>\n", num )
+ }
+ }
+
+ BEGIN {
+ start()
+ }
+
+ /Source:/ {
+ gsub( "../src", "src", $0 ) # sonar doesnt view test dir as root, so strip
+ n = split( $0, a, ":" )
+ if( fip ) {
+ end_file()
+ }
+ fip = 1
+ start_file( a[n] )
+ next;
+ }
+
+ /-:/ { next } # not executable
+
+ /#####:/ { # never executed
+ bad_line( $2 + 0 )
+ next
+ }
+
+ {
+ good_line( $2 + 0 )
+ }
+
+ END {
+ if( fip ) {
+ end_file();
+ }
+
+ end()
+ }
+' $1
+
+exit $/
+
// : vi ts=4 sw=4 noet :
/*
==================================================================================
- Copyright (c) 2019 Nokia
+ Copyright (c) 2019 Nokia
Copyright (c) 2018-2019 AT&T Intellectual Property.
Licensed under the Apache License, Version 2.0 (the "License");
errors += fail_not_nil( buf, "rmr_get_src returned a pointer when given a nil dest buffer" );
buf = rmr_get_src( mbuf, src_buf );
- errors += fail_not_equal( buf, src_buf, "rmr_get_src didn't return expexted buffer pointer" );
+ errors += fail_not_equal( (int) buf, (int) src_buf, "rmr_get_src didn't return expexted buffer pointer" );
return errors > 0; // overall exit code bad if errors
new_msg->header = new_msg->tp_buf;
new_msg->alloc_len = 2048;
new_msg->len = msg->len;
-
+
return new_msg;
}
--- /dev/null
+// :vi sw=4 ts=4 noet:
+/*
+==================================================================================
+ Copyright (c) 2019 Nokia
+ Copyright (c) 2018-2019 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_nano_test.c
+ Abstract: This tests the whole rmr nanomsg 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.
+
+ This test only needs to drive the soruce in nanomsg/src. The
+ common library functions are driven by the nng tests.
+
+ 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>
+
+#define DEBUG 1
+
+#include <nanomsg/nn.h>
+//#include <nng/protocol/pubsub0/pub.h>
+//#include <nng/protocol/pubsub0/sub.h>
+//#include <nng/protocol/pipeline0/push.h>
+//#include <nng/protocol/pipeline0/pull.h>
+
+#undef EMULATE_NNG
+#include "test_nng_em.c" // nng/nn emulation (before including things under test)
+
+
+#include "../src/common/include/rmr.h" // things the users see
+#include "../src/common/include/rmr_symtab.h"
+#include "../src/common/include/rmr_agnostic.h" // transport agnostic header
+#include "../src/nanomsg/include/rmr_private.h" // transport specific
+
+#include "../src/common/src/symtab.c"
+#include "../src/nanomsg/src/rmr.c"
+#include "../src/common/src/mbuf_api.c"
+#include "../src/nanomsg/src/rtable_static.c"
+
+static void gen_rt( uta_ctx_t* ctx ); // defined in sr_static_test, but used by a few others (eliminate order requirement below)
+
+ // specific test tools in this directory
+#include "test_support.c" // things like fail_if()
+ // 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_nano_static_test.c"
+#include "rmr_nng_api_static_test.c" // this can be used for both nng and nano
+#include "rt_nano_static_test.c" // this can be used for both
+
+
+/*
+ Drive each of the separate tests and report.
+*/
+int main() {
+ int errors = 0;
+
+ fprintf( stderr, "<INFO> starting RMr Nanomsg based API tests\n" );
+ errors += rmr_api_test();
+ fprintf( stderr, "<INFO> error count: %d\n", errors );
+
+ fprintf( stderr, "<INFO> starting mbuf related tests\n" );
+ errors += mbuf_api_test( );
+ fprintf( stderr, "<INFO> error count: %d\n", errors );
+
+ fprintf( stderr, "<INFO> starting send/receive tests\n" );
+ errors += sr_nano_test(); // test the send/receive static functions
+ fprintf( stderr, "<INFO> error count: %d\n", errors );
+
+ fprintf( stderr, "<INFO> starting rt_static tests\n" );
+ errors += rt_test(); // route table things specific to nano
+ fprintf( stderr, "<INFO> error count: %d\n", errors );
+
+ if( errors == 0 ) {
+ fprintf( stderr, "<PASS> all tests were OK\n" );
+ } else {
+ fprintf( stderr, "<FAIL> %d modules reported errors\n", errors );
+ }
+
+ return !!errors;
+}
Mmemonic: rmr_api_static_test.c
Abstract: Specific tests related to the API functions in rmr_nng.c/rmr.c.
This should be included by a driver, but only the main RMr
- driver and there likely not be a specific stand alone driver
+ driver and there will likely not be a specific stand alone driver
for just this small set of tests because of the depth of the
library needed to test at this level.
+ This can be used for both the nng and nanomsg outward facing
+ RMr API functions.
+
The message buffer specific API tests are in a different static
module. API functions tested here are:
rmr_close
#include "../src/common/include/rmr.h"
#include "../src/common/include/rmr_agnostic.h"
-//#include "../src/common/src/ring_static.c"
/*
Send a 'burst' of messages to drive some send retry failures to increase RMr coverage
int state;
v = rmr_ready( NULL );
- errors += fail_if( v != 0, "rmr_ready returned true before initialisation" );
+ errors += fail_if( v != 0, "rmr_ready returned true before initialisation " );
if( (rmc = rmr_init( "4560", 1024, FL_NOTHREAD )) == NULL ) {
- fail_if_nil( rmc, "rmr_init returned a nil pointer" );
+ fail_if_nil( rmc, "rmr_init returned a nil pointer " );
return 1;
}
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" );
+ errors += fail_if_nil( rmc, "rmr_init returned a nil pointer for non-threaded init " );
}
free_ctx( rmc2 ); // coverage
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" );
+ errors += fail_if_nil( rmc, "rmr_init returned a nil pointer when driving for default port " );
}
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" );
+ 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" );
+ errors += fail_if_nil( msg, "rmr_alloc_msg returned nil msg pointer " );
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" );
+ 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" );
+ 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" );
+ errors += fail_if( v < 0, "rmr_payload_size returned invalid size for good message " );
}
+#ifdef EMULATE_NNG
+ // this is only supported in nng, so behavour is different depending on the underlying library being tested
+ 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 " );
+#else
v = rmr_get_rcvfd( NULL );
- errors += fail_if( v >= 0, "rmr_get_rcvfd returned a valid file descriptor when given nil context" );
+ 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" );
+ errors += fail_if( v >= 0, "rmr_get_rcvfd returned a valid file descriptor (not supported in nanomsg)" );
+#endif
msg2 = rmr_send_msg( NULL, NULL ); // drive for coverage
- errors += fail_not_nil( msg2, "send_msg returned msg pointer when given a nil message and context" );
+ 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" );
+ 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->state = 999;
errno = 999;
msg = rmr_send_msg( rmc, msg );
- errors += fail_if_nil( msg, "send_msg_ did not return a message on send" );
+ errors += fail_if_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_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 " );
}
gen_rt( rmc ); // --- after this point there is a dummy route table so send and rts calls should be ok
msg->state = 999;
errno = 999;
msg = rmr_send_msg( rmc, msg );
- errors += fail_if_nil( msg, "send_msg_ did not return a message on send" );
+ errors += fail_if_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" );
+ 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( v != 2048, "send_msg did not allocate new buffer with correct size " );
}
rmr_set_stimeout( NULL, 0 );
rmr_set_rtimeout( rmc, -1 );
msg2 = rmr_rcv_msg( NULL, NULL );
- errors += fail_if( msg2 != NULL, "rmr_rcv_msg returned msg when given nil context and msg" );
+ 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" );
+ errors += fail_if( msg2 == NULL, "rmr_rcv_msg returned nil msg when given nil msg " );
if( msg2 ) {
- errors += fail_not_equal( msg2->state, RMR_OK, "receive given nil message did not return msg with good state" );
+ if( msg2->state != RMR_ERR_EMPTY ) {
+ errors += fail_not_equal( msg2->state, RMR_OK, "receive given nil message did not return msg with good state (not empty) " );
+ }
+ //errors += fail_not_equal( msg2->state, RMR_OK, "receive given nil message did not return msg with good state " );
}
+
msg = rmr_rcv_msg( rmc, msg );
if( msg ) {
- errors += fail_if( msg->state != RMR_OK, "rmr_rcv_msg did not return an ok state" );
- errors += fail_not_equal( msg->len, 129, "rmr_rcv_msg returned message with invalid len" );
+ 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" );
+ 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" );
+ 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
- errors += fail_if_equal( msg->state, 0, "rmr_rts_msg did not set state when given valid message but no context" );
-
+ errors += fail_if_equal( msg->state, 0, "rmr_rts_msg did not set state when given valid message but no context " );
+
msg = rmr_rts_msg( rmc, msg ); // return the buffer to the sender
- errors += fail_if_nil( msg, "rmr_rts_msg did not return a message pointer" );
- errors += fail_if( errno != 0, "rmr_rts_msg did not reset errno" );
+ errors += fail_if_nil( msg, "rmr_rts_msg did not return a message pointer " );
+ errors += fail_if( errno != 0, "rmr_rts_msg did not reset errno " );
snprintf( msg->xaction, 17, "%015d", 16 ); // dummy transaction id (emulation generates, this should arrive after a few calls to recv)
msg->state = 0;
msg = rmr_call( NULL, msg );
- errors += fail_if( msg->state == 0, "rmr_call did not set message state when given message with nil context" );
+ errors += fail_if( msg->state == 0, "rmr_call did not set message state when given message with nil context " );
msg->mtype = 0;
msg = rmr_call( rmc, msg ); // this call should return a message as we can anticipate a dummy message in
- errors += fail_if_nil( msg, "rmr_call returned a nil message on call expected to succeed" );
+ 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" );
+ errors += fail_not_equal( msg->state, RMR_OK, "rmr_call did not properly set state on successful return " );
+ errors += fail_not_equal( errno, 0, "rmr_call did not properly set errno (a) on successful return " );
}
snprintf( wbuf, 17, "%015d", 14 ); // if we call receive we should find this in the first 15 tries
}
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_nil( msg, "receive returnd nil msg while looking for queued message " );
}
}
- errors += fail_if( i >= 16, "did not find expected message on queue" );
+ 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 = rmr_call( rmc, msg ); // make a call that we never expect a response on
- errors += fail_if_nil( msg, "rmr_call returned a non-nil message on call expected not to receive a response" );
+ errors += fail_if_nil( msg, "rmr_call returned a non-nil message on call expected not to receive a response " );
if( msg ) {
- errors += fail_if_equal( msg->state, RMR_OK, "rmr_call did not properly set state on queued message receive" );
- errors += fail_if( errno == 0, "rmr_call did not properly set errno on queued message receivesuccessful" );
+ errors += fail_if_equal( msg->state, RMR_OK, "rmr_call did not properly set state on queued message receive " );
+ errors += fail_if( errno == 0, "rmr_call did not properly set errno on queued message receivesuccessful " );
}
msg = rmr_call( rmc, msg ); // this should "timeout" because the message xaction id won't ever appear again
- errors += fail_if_nil( msg, "rmr_call returned a nil message on call expected to fail (but return a pointer)" );
- errors += fail_if( errno == 0, "rmr_call did not set errno on failure" );
+ errors += fail_if_nil( msg, "rmr_call returned a nil message on call expected to fail " );
+ 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" );
+ 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" );
+ 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" );
+ errors += fail_if_nil( msg, "torcv_msg returned nil msg when message expected " );
if( msg ) {
- if( msg->state == RMR_ERR_TIMEOUT ) { // queue drained and we've seen both states from poll if we get a timeout
+ 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" );
+ 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" );
+ 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" );
+ 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" );
+ 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)" );
+ 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" );
+ 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
--- /dev/null
+// : vi ts=4 sw=4 noet :
+/*
+==================================================================================
+ Copyright (c) 2019 Nokia
+ Copyright (c) 2018-2019 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: rt_static_test.c
+ Abstract: Test the route table funcitons. These are meant to be included at compile
+ time by the test driver.
+
+ Author: E. Scott Daniels
+ Date: 3 April 2019
+*/
+
+#include <unistd.h>
+#include <stdio.h>
+#include <stdlib.h>
+#include <strings.h>
+#include <errno.h>
+#include <string.h>
+#include <stdint.h>
+
+#include "../src/common/include/rmr.h"
+#include "../src/common/include/rmr_agnostic.h"
+
+typedef struct entry_info {
+ int group;
+ char* ep_name;
+} ei_t;
+
+/*
+ Create a dummy endpoint for some direct function calls.
+*/
+static endpoint_t* mk_ep( char* name ) {
+ endpoint_t* ep;
+
+ ep = (endpoint_t *) malloc( sizeof( struct endpoint ) );
+ ep->name = strdup( name );
+ ep->proto = strdup( "tcp" );
+ ep->addr = strdup( "address" );
+ ep->nn_sock = -1;
+ ep->open = 0;
+
+ return ep;
+}
+
+
+/*
+ This is the main route table test. It sets up a very specific table
+ for testing (not via the generic setup function for other test
+ situations).
+*/
+static int rt_test( ) {
+ uta_ctx_t* ctx; // context needed to test load static rt
+ route_table_t* rt; // route table
+ route_table_t* crt; // cloned route table
+ rtable_ent_t* rte; // entry in the table
+ endpoint_t* ep; // endpoint added
+ int more = 0; // more flag from round robin
+ int errors = 0; // number errors found
+ int i;
+ int k;
+ int mtype;
+ int value;
+ int alt_value;
+ ei_t entries[50]; // end point information
+ int gcounts[5]; // number of groups in this set
+ int ecounts[5]; // number of elements per group
+ int mtypes[5]; // msg type for each group set
+ char* tok;
+ char* nxt_tok;
+ int enu = 0;
+ int state;
+ char *buf;
+ char* seed_fname; // seed file
+ int nn_sock;
+
+ 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 ) {
+ write( i, "2\n", 2 );
+ close( i );
+ }
+
+ gcounts[0] = 1; // build entry info -- this is hackish, but saves writing another parser
+ ecounts[0] = 2;
+ mtypes[0] = 0;
+ entries[enu].group = 0; entries[enu].ep_name = "yahoo.com:4561"; enu++; // use a dns resolvable name to test that
+ entries[enu].group = 0; entries[enu].ep_name = "localhost:4562"; enu++; // rest can default to some dummy ip
+
+ gcounts[1] = 2;
+ ecounts[1] = 3;
+ mtypes[1] = 1;
+ entries[enu].group = 0; entries[enu].ep_name = "localhost:4561"; enu++;
+ entries[enu].group = 0; entries[enu].ep_name = "localhost:4568"; enu++;
+ entries[enu].group = 0; entries[enu].ep_name = "localhost:4569"; enu++;
+
+ gcounts[2] = 0; // 0 groups means use same rte, this is the next gropup
+ ecounts[2] = 2;
+ mtypes[2] = 1;
+ entries[enu].group = 1; entries[enu].ep_name = "localhost:4561"; enu++;
+ entries[enu].group = 1; entries[enu].ep_name = "localhost:4562"; enu++;
+
+ gcounts[3] = 1; // 0 groups means use same rte, this is the next gropup
+ ecounts[3] = 2;
+ mtypes[3] = 2;
+ entries[enu].group = 0; entries[enu].ep_name = "localhost:4563"; enu++;
+ entries[enu].group = 0; entries[enu].ep_name = "localhost:4564"; enu++;
+
+ gcounts[4] = 1; // 0 groups means use same rte, this is the next gropup
+ ecounts[4] = 1;
+ mtypes[4] = 3;
+ entries[enu].group = 0; entries[enu].ep_name = "localhost:4565"; enu++;
+
+
+ rt = uta_rt_init( ); // get us a route table
+ if( (errors += fail_if_nil( rt, "pointer to route table" )) ) {
+ fprintf( stderr, "<FAIL> abort: cannot continue without a route table\n" );
+ exit( 1 );
+ }
+
+ enu = 0;
+ rte = NULL;
+ for( i = 0; i < sizeof( gcounts )/sizeof( int ); i++ ) { // add entries defined above
+ if( gcounts[i] ) {
+ rte = uta_add_rte( rt, mtypes[i], gcounts[i] ); // get/create entry for message type
+ if( (errors += fail_if_nil( rte, "route table entry" )) ) {
+ fprintf( stderr, "<FAIL> abort: cannot continue without a route table entry\n" );
+ exit( 1 );
+ }
+ } else {
+ if( rte == NULL ) {
+ fprintf( stderr, "<SNAFU> internal testing error -- rte was nil for gcount == 0\n" );
+ exit( 1 );
+ }
+ }
+
+ for( k = 0; k < ecounts[i]; k++ ) {
+ ep = uta_add_ep( rt, rte, entries[enu].ep_name, entries[enu].group );
+ errors += fail_if_nil( ep, "endpoint" );
+ enu++;
+ }
+ }
+
+ crt = uta_rt_clone( rt );
+ errors += fail_if_nil( crt, "cloned route table" );
+
+ ep = uta_get_ep( rt, "localhost:4561" );
+ errors += fail_if_nil( ep, "end point (fetch by name)" );
+ ep = uta_get_ep( rt, "bad_name:4560" );
+ errors += fail_not_nil( ep, "end point (fetch by name with bad name)" );
+
+ state = uta_epsock_byname( rt, "localhost:4561" ); // this should be found
+ errors += fail_if_true( state < 0, "socket (by name) returned socket less than 0 when expected >= 0 socket" );
+
+ alt_value = -1;
+ for( i = 0; i < 10; i++ ) { // round robin return value should be different each time
+ value = uta_epsock_rr( rt, 1, 0, &more ); // nano returns the socket which should be different than the last call
+ 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;
+ }
+
+ more = -1;
+ for( i = 0; i < 10; i++ ) { // this mtype has only one endpoint, so rr should be same each time
+ value = uta_epsock_rr( rt, 3, 0, NULL ); // also test ability to deal properly with nil more pointer
+ 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" );
+ }
+ alt_value = value;
+ }
+
+ value = uta_epsock_rr( rt, 289486, 0, &more ); // non-existant message type; should return false (0)
+ errors += fail_if_true( value >= 0, "socket for bad hash key was valid" );
+
+ uta_rt_clone( NULL ); // verify null parms don't crash things
+ uta_rt_drop( NULL );
+ uta_epsock_rr( NULL, 1, 0, &more ); // drive null case for coverage
+ uta_add_rte( NULL, 99, 1 );
+
+ fprintf( stderr, "<INFO> adding end points with nil data; warnings from RMr code are expected\n" );
+ uta_add_ep( NULL, NULL, "foo", 1 );
+ uta_add_ep( rt, NULL, "foo", 1 );
+
+ buf = uta_fib( ".gitignore" );
+ errors += fail_if_nil( buf, "buffer from read file into buffer" );
+ if( buf ) {
+ free( buf );
+ }
+ buf = uta_fib( "no-file" );
+ errors += fail_if_nil( buf, "buffer from read file into buffer (no file)" );
+ if( buf ) {
+ free( buf );
+ }
+
+ uta_rt_drop( rt );
+
+ uta_rt_drop( crt );
+
+ if( (ctx = (uta_ctx_t *) malloc( sizeof( uta_ctx_t ) )) != NULL ) {
+ memset( ctx, 0, sizeof( *ctx ) );
+
+ if( (seed_fname = getenv( "RMR_SEED_RT" )) != NULL ) {
+ if( ! (fail_if_nil( rt, "pointer to rt for load test" )) ) {
+ read_static_rt( ctx, 0 );
+ unsetenv( "RMR_SEED_RT" ); // unset to test the does not exist condition
+ read_static_rt( ctx, 0 );
+ } else {
+ fprintf( stderr, "<FAIL> cannot gen rt for load test\n" );
+ }
+ } else {
+ read_static_rt( ctx, 0 ); // not defined, just drive for that one case
+ }
+ }
+
+ uta_fib( "no-suhch-file" ); // drive some error checking for coverage
+
+ rt = uta_rt_init( ); // get us a route table
+ state = uta_link2( NULL );
+ errors += fail_not_equal( state, -1, "link2 did not return (a==) -1 when given nil pointers" );
+
+ ep = mk_ep( "foo" );
+ state = rt_link2_ep( NULL );
+ errors += fail_not_equal( state, 0, "link2_ep did not return (a) bad when given nil pointers" );
+
+ state = rt_link2_ep( ep );
+ errors += fail_not_equal( state, 1, "link2_ep did not return (a) bad when given an ep to use to open" );
+
+ ep->open = 1;
+ state = rt_link2_ep( ep );
+ errors += fail_not_equal( state, 1, "link2_ep did not return (a) bad when given an ep which was set open" );
+
+ state = uta_epsock_rr( rt, 122, 0, NULL );
+ errors += fail_not_equal( state, -1, "uta_epsock_rr returned bad state when given nil socket pointer" );
+
+ state = uta_epsock_rr( rt, 0, -1, NULL );
+ errors += fail_not_equal( state, -1, "uta_epsock_rr returned bad state (a) when given negative group number" );
+
+ state = rt_link2_ep( NULL );
+ errors += fail_if_equal( state, -1, "call to link2_ep with nil ep returned true when false expected" );
+
+
+ return !!errors; // 1 or 0 regardless of count
+}
// : vi ts=4 sw=4 noet :
/*
==================================================================================
- Copyright (c) 2019 Nokia
+ Copyright (c) 2019 Nokia
Copyright (c) 2018-2019 AT&T Intellectual Property.
Licensed under the Apache License, Version 2.0 (the "License");
/*
Mmemonic: rt_static_test.c
Abstract: Test the route table funcitons. These are meant to be included at compile
- time by the test driver.
+ time by the test driver.
Author: E. Scott Daniels
Date: 3 April 2019
state = uta_link2( "worm", NULL, NULL );
errors += fail_if_true( state, "link2 did not return false when given nil pointers" );
-
+
state = uta_epsock_rr( rt, 122, 0, NULL, NULL );
errors += fail_if_true( state, "uta_epsock_rr returned bad state when given nil socket pointer" );
--- /dev/null
+// : vi ts=4 sw=4 noet :
+/*
+==================================================================================
+ Copyright (c) 2019 Nokia
+ Copyright (c) 2018-2019 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_nano_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: 3 April 2019
+*/
+
+#include <unistd.h>
+#include <stdio.h>
+#include <stdlib.h>
+#include <strings.h>
+#include <errno.h>
+#include <string.h>
+#include <stdint.h>
+
+#include "../src/common/include/rmr.h"
+#include "../src/common/include/rmr_agnostic.h"
+
+/*
+ Generate a simple route table (for all but direct route table testing).
+*/
+static void gen_rt( uta_ctx_t* ctx ) {
+ int fd;
+ char* rt_stuff; // strings for the route table
+
+ rt_stuff =
+ "newrt|end\n" // end of table check before start of table found
+ "# comment to drive full comment test\n"
+ "\n" // handle blank lines
+ " \n" // handle blank lines
+ "mse|4|10|localhost:4561\n" // entry before start message
+ "rte|4|localhost:4561\n" // entry before start message
+ "newrt|start\n" // false start to drive detection
+ "xxx|badentry to drive default case"
+ "newrt|start\n"
+ "rte|0|localhost:4560,localhost:4562\n" // these are legitimate entries for our testing
+ "rte|1|localhost:4562;localhost:4561,localhost:4569\n"
+ "rte|2|localhost:4562| 10\n" // new subid at end
+ "mse|4|10|localhost:4561\n" // new msg/subid specifier rec
+ "mse|4|localhost:4561\n" // new mse entry with less than needed fields
+ " rte| 5 |localhost:4563 #garbage comment\n" // tests white space cleanup
+ "rte|6|localhost:4562\n"
+ "newrt|end\n";
+
+ fd = open( "utesting.rt", O_WRONLY | O_CREAT, 0600 );
+ if( fd < 0 ) {
+ fprintf( stderr, "<BUGGERED> unable to open file for testing route table gen\n" );
+ return;
+ }
+
+ setenv( "RMR_SEED_RT", "utesting.rt", 1 );
+ write( fd, rt_stuff, strlen( rt_stuff ) );
+ close( fd );
+ read_static_rt( ctx, 0 );
+ unlink( "utesting.rt" );
+}
+
+
+/*
+ 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_nano_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.
+*/
+static int sr_nano_test() {
+ int errors = 0; // number errors found
+
+ 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
+ rmr_mbuf_t* mbuf; // mbuf to send/receive
+ rmr_mbuf_t* mb2; // error capturing msg buf
+ int whid = -1;
+ int last_whid;
+ int state;
+ int nn_dummy_sock; // dummy needed to drive send
+ int size;
+ int i;
+ void* p;
+
+ //ctx = rmr_init( "tcp:4360", 2048, 0 ); // do NOT call init -- that starts the rtc thread which isn't good here
+ ctx = (uta_ctx_t *) malloc( sizeof( uta_ctx_t ) ); // alloc the context manually
+ memset( ctx, 0, sizeof( uta_ctx_t ) );
+
+ ctx->mring = NULL; //uta_mk_ring( 128 );
+ 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" );
+ 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" );
+
+ mbuf = rcv_msg( ctx, NULL );
+ errors += fail_if_nil( mbuf, "no mbuf returned on receive test" );
+
+ 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 );
+ }
+
+ size = 4096;
+ state = rmr_payload_size( mbuf );
+ errors += fail_not_equal( state, size, "payload size (b) didn't return expected value (a)" ); // receive should always give 4k buffer
+
+ rmr_free_msg( mbuf );
+
+
+ // ---- direct message read into payload (no rmr header) -------------------------
+ mbuf = rcv_payload( ctx, NULL );
+ errors += fail_if_nil( mbuf, "rcv_payload did not return a message buffer when given a nil messge" );
+ if( mbuf ) {
+ errors += fail_if_true( mbuf->len <= 0, "rcv_payload did not return a buffer with payload length set when given a nil messge" );
+ errors += fail_not_equal( mbuf->state, 0, "rcv_payload did not return a buffer with good state when given a nil messge" );
+ }
+
+ mbuf = rcv_payload( ctx, NULL );
+ errors += fail_if_nil( mbuf, "rcv_payload did not return a message buffer" );
+ if( mbuf ) {
+ errors += fail_if_true( mbuf->len <= 0, "rcv_payload did not return a buffer with payload length set" );
+ errors += fail_not_equal( mbuf->state, 0, "rcv_payload did not return a buffer with good state" );
+ }
+
+ // ---- drive rtc in a 'static' (not pthreaded) mode to get some coverage; no 'results' to be verified -----
+ setenv( ENV_RTG_RAW, "1", 1 ); // rtc should expect raw messages (mostly coverage here)
+ 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 );
+
+
+ // --- drive the route table things which are nanomsg specific ------
+
+ return !!errors;
+}
#define _em_nn
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
// ----------- epoll emulation ---------------------------------------------
-//--------------------------------------------------------------------------
-#ifdef EMULATE_NNG
-struct nn_msghdr {
- int boo;
-};
-
-static int return_value = 0;
-
-/*
- Test app can call this to have all emulated functions return failure instead
- of success.
-*/
-static void en_set_retur( int rv ) {
- return_value = rv;
-}
-
-
-
-static int em_nng_foo() {
- fprintf( stderr, "emulated functions in play" );
-}
-
-
/*
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.
};
+static int return_value = 0;
+
+//--------------------------------------------------------------------------
+#ifdef EMULATE_NNG
+struct nn_msghdr {
+ int boo;
+};
+
+
+/*
+ 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" );
+}
+
+
/*
Receive message must allocate a new buffer and return the pointer into *m.
Every 9 messages or so we'll simulate an old version message
msg->rmr_ver = htonl( MSG_VER );
}
msg->mtype = htonl( 1 );
- msg->plen = htonl( 129 );
+ msg->plen = htonl( 220 );
msg->len0 = htonl( sizeof( struct em_msg ) );
msg->len1 = htonl( trace_size );
snprintf( msg->xid, 32, "%015d", count++ ); // simple transaction id so we can test receive specific and ring stuff
return return_value;
}
static int em_nng_recv(nng_socket s, void * v, size_t * t, int i ) {
+
return return_value;
}
static int em_nng_send( nng_socket s, void* m, int l, int f ) {
return 1;
}
-static int em_nn_setsockopt (int s, int level, int option, const void *optval, size_t optvallen ) {
- return 1;
-}
+//static int em_nn_setsockopt (int s, int level, int option, const void *optval, size_t optvallen ) {
+ //return 1;
+//}
static int em_nn_getsockopt (int s, int level, int option, void *optval, size_t *optvallen ) {
return 1;
}
static int em_nn_bind (int s, const char *addr ) {
-fprintf( stderr, ">>> ===== emulated bind called ====\n" );
+ // fprintf( stderr, ">>> ===== emulated bind called ====\n" );
return 1;
}
return 1;
}
-static int em_nn_recv (int s, void *buf, size_t len, int flags ) {
- return 1;
+static int em_nn_recv (int s, void *m, size_t len, int flags ) {
+ void* b;
+ struct em_msg* msg;
+ static int count = 0; // we'll simulate a message going in by dropping an rmr-ish msg with transaction id only
+ int trace_size = 0;
+ static int counter = 0; // if timeout value is set; we return timeout (eagain) every 3 calls
+
+ if( em_timeout > 0 ) {
+ counter++;
+ if( counter % 3 == 0 ) {
+ return EAGAIN;
+ }
+ }
+
+ b = (void *) malloc( 2048 );
+ if( m != NULL ) { // blindly we assume this is 2k or bigger
+ memset( m, 0, 2048 );
+ msg = (struct em_msg *) m;
+ if( count % 10 == 9 ) {
+ //msg->rmr_ver = htonl( MSG_VER );
+ msg->rmr_ver = ALT_MSG_VER; // emulate the bug in RMr v1
+ } else {
+ msg->rmr_ver = htonl( MSG_VER );
+ }
+ msg->mtype = htonl( 1 );
+ msg->plen = htonl( 220 );
+ msg->len0 = htonl( sizeof( struct em_msg ) );
+ msg->len1 = htonl( trace_size );
+ snprintf( msg->xid, 32, "%015d", count++ ); // simple transaction id so we can test receive specific and ring stuff
+ snprintf( msg->src, 16, "localhost:4562" ); // set src id (unrealistic) so that rts() can be tested
+ //fprintf( stderr, "<EM> returning message len=%d\n\n", ntohl( msg->plen ) );
+ } else {
+ fprintf( stderr, "<EM> message was nil\n\n" );
+ }
+
+ //fprintf( stderr, ">>> simulated received message: %s len=%d\n", msg->xid, msg->plen );
+ return 2048;
}
static int em_sendmsg (int s, const struct em_nn_msghdr *msghdr, int flags ) {
return 1;
}
+static void em_nn_freemsg( void* ptr ) {
+ return;
+}
+
+/*
+ Hacky implementation of set sock opt. We assume value is a pointer to int and ignore size.
+*/
+static int em_setsockopt( int sock, int foo, int action, int* value, int size ) {
+ if( action == NN_RCVTIMEO ) {
+ em_timeout = *value;
+ }
+}
+
+
// nanomsg
#define nn_socket em_nn_socket
#define nn_close em_nn_close
-#define nn_setsockopt em_nn_setsockopt
+//#define nn_setsockopt em_nn_setsockopt
#define nn_getsockopt em_nn_getsockopt
#define nn_bind em_nn_bind
#define nn_connect em_nn_connect
#define nn_recv em_nn_recv
#define nn_sendmsg em_nn_sendmsg
#define nn_recvmsg em_nn_recvmsg
+#define nn_setsockopt em_setsockopt
+#define nn_freemsg em_nn_freemsg
#endif
# this will fail if run with bash!
#==================================================================================
-# Copyright (c) 2019 Nokia
+# Copyright (c) 2019 Nokia
# Copyright (c) 2018-2019 AT&T Intellectual Property.
#
# Licensed under the Apache License, Version 2.0 (the "License");
#
# Mnemonic: unit_test.ksh
-# Abstract: Execute unit test(s) in the directory and produce a more
+# Abstract: Execute unit test(s) in the directory and produce a more
# meaningful summary than gcov gives by default (exclude
# coverage on the unit test functions).
#
-# Test files must be named *_test.c, or must explicitly be
+# Test files must be named *_test.c, or must explicitly be
# supplied on the command line. Functions in the test
# files will not be reported on provided that they have
# their prototype (all on the SAME line) as:
# static type name() {
#
-# Functions with coverage less than 80% will be reported as
+# Functions with coverage less than 80% will be reported as
# [LOW] in the output. A file is considered to pass if the
# overall execution percentage for the file is >= 80% regardless
# of the number of functions that reported low.
#
# Test programmes are built prior to execution. Plan-9 mk is
# the preferred builder, but as it's not widly adopted (sigh)
-# make is assumed and -M will shift to Plan-9. Use -C xxx to
+# make is assumed and -M will shift to Plan-9. Use -C xxx to
# invoke a customised builder.
#
# For a module which does not pass, we will attempt to boost
# the coverage by discounting the unexecuted lines which are
-# inside of if() statements that are checking return from
+# inside of if() statements that are checking return from
# (m)alloc() calls or are checking for nil pointers as these
# cases are likely impossible to drive. When discount testing
# is done both the failure message from the original analysis
-# and a pass/fail message from the discount test are listed,
-# but only the result of the discount test is taken into
+# and a pass/fail message from the discount test are listed,
+# but only the result of the discount test is taken into
# consideration with regard to overall success.
#
# Overall Pass/Fail
# By default the overall state is based only on the success
-# or failure of the unit tests and NOT on the perceived
+# or failure of the unit tests and NOT on the perceived
# state of coverage. If the -s (strict) option is given, then
# overall state will be failure if code coverage expectations
# are not met.
# -------------------------------------------------------------------------
function usage {
- echo "usage: $0 [-G|-M|-C custom-command-string] [-c cov-target] [-f] [-F] [-v] [files]"
+ echo "usage: $0 [-G|-M|-C custom-command-string] [-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 " -F show only failures at the function level"
echo " -s strict mode; code coverage must also pass to result in a good exit code"
echo " -v will write additional information to the tty and save the disccounted file if discount run or -f given"
+ echo " -x generates the coverage XML files for Sonar (implies -f)"
}
-# read through the given file and add any functions that are static to the
+# read through the given file and add any functions that are static to the
# ignored list. Only test and test tools files should be parsed.
#
function add_ignored_func {
typeset f=""
grep "^static.*(.*).*{" $1 | awk ' # get list of test functions to ignore
- {
+ {
gsub( "[(].*", "" )
print $3
}
' | while read f
do
- iflist="${iflist}$f "
+ iflist="${iflist}$f "
done
}
+
+# Merge two coverage files to preserve the total lines covered by different
+# test programmes.
#
-# Parse the .gcov file and discount any unexecuted lines which are in if()
+function merge_cov {
+ if [[ -z $1 || -z $2 ]]
+ then
+ return
+ fi
+
+ if [[ ! -e $1 || ! -e $2 ]]
+ then
+ return
+ fi
+
+ (
+ cat $1
+ echo "==merge=="
+ cat $2
+ ) | awk '
+ /^==merge==/ {
+ merge = 1
+ next
+ }
+
+ merge && /#####:/ {
+ line = $2+0
+ if( executed[line] ) {
+ $1 = sprintf( "%9d:", executed[line] )
+ }
+ }
+
+ merge {
+ print
+ next
+ }
+
+ {
+ line = $2+0
+ if( $1+0 > 0 ) {
+ executed[line] = $1+0
+ }
+ }
+ '
+}
+
+#
+# Parse the .gcov file and discount any unexecuted lines which are in if()
# blocks that are testing the result of alloc/malloc calls, or testing for
# nil pointers. The feeling is that these might not be possible to drive
# and shoudn't contribute to coverage deficiencies.
then
if [[ -f ${1##*/} ]]
then
- f=${1##*/}
+ f=${1##*/}
else
echo "cant find: $f"
return
-v show_all=$show_all \
-v full_name="${1}" \
-v module="${f%.*}" \
- -v chatty=1 \
+ -v chatty=$chatty \
+ -v replace_flags=$replace_flags \
'
function spit_line( ) {
if( chatty ) {
/-:/ { # skip unexecutable lines
spit_line()
seq++ # allow blank lines in a sequence group
- next
+ next
}
{
if( prev_if && prev_malloc ) {
if( prev_malloc ) {
#printf( "allow discount: %s\n", $0 )
- if( chatty ) {
- gsub( "#####", "=====", $0 )
+ if( replace_flags ) {
+ gsub( "#####", " 1", $0 )
+ //gsub( "#####", "=====", $0 )
}
discount++;
}
next
}
- {
+ {
spit_line()
}
rc = adj_cov < module_cov_target ? 1 : 0
if( pass_fail == cfail || show_all ) {
if( chatty ) {
- printf( "[%s] %s executable=%d unexecuted=%d discounted=%d net_unex=%d cov=%d%% ==> %d%% target=%d%%\n",
+ printf( "[%s] %s executable=%d unexecuted=%d discounted=%d net_unex=%d cov=%d%% ==> %d%% target=%d%%\n",
pass_fail, full_name ? full_name : module, nexec, unexec, discount, net, orig_cov, adj_cov, module_cov_target )
} else {
printf( "[%s] %d%% (%d%%) %s\n", pass_fail, adj_cov, orig_cov, full_name ? full_name : module )
' $f
}
-# Given a file name ($1) see if it is in the ./.targets file. If it is
+# Given a file name ($1) see if it is in the ./.targets file. If it is
# return the coverage listed, else return (echo) the default $module_cov_target
#
function get_mct {
echo ${tv:-$v}
}
+# Remove unneeded coverage files, then generate the xml files that can be given
+# to sonar. gcov.xml is based on the "raw" coverage and dcov.xml is based on
+# the discounted coverage.
+#
+function mk_xml {
+ rm -fr *_test.c.gcov test_*.c.gcov *_test.c.dcov test_*.c.dcov # we don't report on the unit test code, so ditch
+ cat *.gcov | cov2xml.ksh >gcov.xml
+ cat *.dcov | cov2xml.ksh >dcov.xml
+}
-# ------------------------------------------------------------------------
+
+# -----------------------------------------------------------------------------------------------------------------
# we assume that the project has been built in the ../[.]build directory
if [[ -d ../build/lib ]]
if [[ -d ../.build/lib ]]
then
export LD_LIBRARY_PATH=../.build/lib
+ export C_INCLUDE_PATH=../.build/include
+
else
echo "[WARN] cannot find ../[.]build/lib; things might not work"
echo ""
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
while [[ $1 == "-"* ]]
do
- case $1 in
+ case $1 in
-C) builder="$2"; shift;; # custom build command
-G) builder="gmake %s";;
-M) builder="mk -a %s";; # use plan-9 mk (better, but sadly not widly used)
-c) module_cov_target=$2; shift;;
- -f) force_discounting=1;
+ -f) force_discounting=1;
trigger_discount_str="WARN|FAIL|PASS" # check all outcomes for each module
;;
-S) show_output=1;; # test output shown even on success
-v) (( verbose++ ));;
-q) quiet=1;; # less chatty when spilling error log files
+ -x) gen_xml=1
+ force_discounting=1
+ trigger_discount_str="WARN|FAIL|PASS" # check all outcomes for each module
+ rm *cov.xml
+ ;;
-h) usage; exit 0;;
--help) usage; exit 0;;
fi
+rm *.gcov # ditch the previous coverage files
ut_errors=0 # unit test errors (not coverage errors)
errors=0
+
for tfile in $flist
do
+ for x in *.gcov
+ do
+ if [[ -e $x ]]
+ then
+ cp $x $x-
+ fi
+ done
+
echo "$tfile --------------------------------------"
bcmd=$( printf "$builder" "${tfile%.c}" )
if ! $bcmd >/tmp/PID$$.log 2>&1
do
add_ignored_func $f
done
-
+
if ! ./${tfile%.c} >/tmp/PID$$.log 2>&1
then
echo "[FAIL] unit test failed for: $tfile"
- if (( quiet ))
+ if (( quiet ))
then
grep "^<" /tmp/PID$$.log # in quiet mode just dump <...> messages which are assumed from the test programme not appl
else
(
touch ./.targets
sed '/^#/ d; /^$/ d; s/^/TARGET: /' ./.targets
- gcov -f ${tfile%.c} | sed "s/'//g"
+ gcov -f ${tfile%.c} | sed "s/'//g"
) | awk \
-v cfail=$cfail \
-v show_all=$show_all \
}
if( target[fname] ) {
- mct = target[fname]
+ mct = target[fname]
announce_target = 1;
} else {
mct = module_cov_target
' >/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
- show_all=1
if (( ! verbose ))
then
echo "[INFO] checking to see if discounting improves coverage for failures listed above"
(( errors++ ))
fi
- tail -1 /tmp/PID$$.disc
+ tail -1 /tmp/PID$$.disc | grep '\['
if (( verbose > 1 )) # updated file was generated, keep here
then
mv /tmp/PID$$.disc ${name##*/}.dcov
done
fi
+
+ for x in *.gcov # merge any previous coverage file with this one
+ do
+ if [[ -e $x && -e $x- ]]
+ then
+ merge_cov $x $x- >/tmp/PID$$.mc
+ cp /tmp/PID$$.mc $x
+ rm $x-
+ fi
+ done
+done
+
+echo ""
+echo "[INFO] final discount checks on merged gcov files"
+show_all=1
+for xx in *.gcov
+do
+ if [[ $xx != *"test"* ]]
+ then
+ of=${xx%.gcov}.dcov
+ discount_an_checks $xx >$of
+ tail -1 $of | grep '\['
+ fi
done
state=0 # final state
echo "[FAIL] overall unit testing fails: coverage errors=$errors unit test errors=$ut_errors"
else
echo "[PASS] overall unit testing passes"
+ if (( gen_xml ))
+ then
+ mk_xml
+ fi
fi
exit $state