1 // : vi ts=4 sw=4 noet :
3 ==================================================================================
4 Copyright (c) 2019-2020 Nokia
5 Copyright (c) 2018-2020 AT&T Intellectual Property.
7 Licensed under the Apache License, Version 2.0 (the "License");
8 you may not use this file except in compliance with the License.
9 You may obtain a copy of the License at
11 http://www.apache.org/licenses/LICENSE-2.0
13 Unless required by applicable law or agreed to in writing, software
14 distributed under the License is distributed on an "AS IS" BASIS,
15 WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
16 See the License for the specific language governing permissions and
17 limitations under the License.
18 ==================================================================================
22 Mmemonic: rmr_si_api_static_test.c
23 Abstract: Specific tests related to the API functions in rmr_si.c.
24 This should be included by a driver which invokes the 'main'
25 test function here: rmr_api_test.
27 This test set applies only to the outward facting API functions
28 in the rmr_si.c module (mostly because the context for SI is
31 The message buffer specific API tests are in a different static
32 module. API functions tested here are:
48 Author: E. Scott Daniels
60 #include <semaphore.h>
63 #include "rmr_agnostic.h"
66 Send a 'burst' of messages to drive some send retry failures to increase RMr coverage
67 by handling the retry caee.
69 static void send_n_msgs( void* ctx, int n ) {
70 rmr_mbuf_t* msg; // message buffers
73 msg = rmr_alloc_msg( ctx, 1024 );
78 for( i = 0; i < n; i++ ) {
79 //fprintf( stderr, "mass send\n" );
84 msg = rmr_send_msg( ctx, msg );
89 Refresh or allocate a message with some default values
91 static rmr_mbuf_t* fresh_msg( void* ctx, rmr_mbuf_t* msg ) {
93 msg = rmr_alloc_msg( ctx, 2048 );
104 static int rmr_api_test( ) {
106 void* rmc; // route manager context
107 void* rmc2; // second context for non-listener init
108 rmr_mbuf_t* msg; // message buffers
110 int v = 0; // some value
114 int max_tries; // prevent a sticking in any loop
116 v = rmr_ready( NULL );
117 errors += fail_if( v != 0, "rmr_ready returned true before initialisation " );
119 em_set_long_hostname( 1 );
120 if( (rmc = rmr_init( "4560", 1024, FL_NOTHREAD )) == NULL ) {
121 fail_if_nil( rmc, "rmr_init returned a nil pointer " );
125 setenv( "RMR_SRC_ID", "somehost", 1 ); // context should have this as source
126 if( (rmc2 = rmr_init( ":6789", 1024, FL_NOTHREAD )) == NULL ) { // init without starting a thread
127 errors += fail_if_nil( rmc, "rmr_init returned a nil pointer for non-threaded init " );
130 fprintf( stderr, "<INFO> with RMR_SRC_ID env set, source name in context: (%s)\n", ((uta_ctx_t *) rmc2)->my_name );
131 v = strcmp( ((uta_ctx_t *) rmc2)->my_name, "somehost:6789" );
132 errors += fail_not_equal( v, 0, "source name not set from environment variable (see previous info)" );
133 free_ctx( rmc2 ); // coverage
135 unsetenv( "RMR_SRC_ID" ); // context should NOT have our artificial name
136 if( (rmc2 = rmr_init( NULL, 1024, FL_NOTHREAD )) == NULL ) { // drive default port selector code
137 errors += fail_if_nil( rmc, "rmr_init returned a nil pointer when driving for default port " );
140 fprintf( stderr, "<INFO> after unset of RMR_SRC_ID, source name in context: (%s)\n", ((uta_ctx_t *) rmc2)->my_name );
141 v = strcmp( ((uta_ctx_t *) rmc2)->my_name, "somehost:6789" );
142 errors += fail_if_equal( v, 0, "source name smells when removed from environment (see previous info)" );
143 free_ctx( rmc2 ); // attempt to reduce leak check errors
145 v = rmr_ready( rmc ); // unknown return; not checking at the moment
147 msg = rmr_alloc_msg( NULL, 1024 ); // should return nil pointer
148 errors += fail_not_nil( msg, "rmr_alloc_msg didn't return nil when given nil context " );
151 msg = rmr_alloc_msg( rmc, 2048 ); // allocate larger than default size given on init
152 errors += fail_if_nil( msg, "rmr_alloc_msg returned nil msg pointer " );
154 rmr_get_srcip( msg, wbuf );
155 errors += fail_if_equal( 0, strlen( wbuf ), "rmr_get_srcip did not did not return string with length (b) after alloc_msg" );
156 fprintf( stderr, "<INFO> ip: %s\n", wbuf );
160 v = rmr_payload_size( NULL );
161 errors += fail_if( v >= 0, "rmr_payload_size returned valid size for nil message " );
162 errors += fail_if( errno == 0, "rmr_payload_size did not set errno on failure " );
164 v = rmr_payload_size( msg );
166 errors += fail_not_equal( v, 2048, "rmr_payload_size returned invalid size (a) instead of expected size (b) " );
167 errors += fail_if( errno != 0, "rmr_payload_size did not clear errno on success " );
169 errors += fail_if( v < 0, "rmr_payload_size returned invalid size for good message " );
174 v = rmr_get_rcvfd( NULL );
175 errors += fail_if( v >= 0, "rmr_get_rcvfd returned a valid file descriptor when given nil context " );
176 v = rmr_get_rcvfd( rmc );
177 errors += fail_if( v < 0, "rmr_get_rcvfd did not return a valid file descriptor " );
179 msg2 = rmr_send_msg( NULL, NULL );
180 errors += fail_not_nil( msg2, "send_msg returned msg pointer when given a nil message and context " );
183 msg = rmr_send_msg( NULL, msg );
184 errors += fail_if( msg->state == 0, "rmr_send_msg did not set msg state when msg given with nil context " );
186 // --- sends will fail with a no endpoint error until a dummy route table is set, so we test fail case first.
192 snprintf( msg->payload, 100, "Stand up and cheer from OU to Oh yea! (1)" );
194 msg = rmr_send_msg( rmc, msg );
195 errors += fail_if_nil( msg, "send_msg_ did not return a message on send " );
197 errors += fail_not_equal( msg->state, RMR_ERR_NOENDPT, "send_msg did not return no endpoints before rtable added " );
198 errors += fail_if( errno == 0, "send_msg did not set errno " );
199 errors += fail_if( msg->tp_state == 999, "send_msg did not set tp_state (1)" );
202 gen_rt( rmc ); // --- after this point there is a dummy route table so send and rts calls should be ok
204 if( ! rmr_ready( rmc ) ) {
205 fprintf( stderr, "\nPANIC! rmr isn't showing ready after loading a rt table\n\n" );
209 state = init_mtcall( NULL ); // drive for coverage
210 errors += fail_not_equal( state, 0, "init_mtcall did not return false (a) when given a nil context pointer" );
213 msg = rmr_alloc_msg( rmc, 2048 ); // get a buffer with a transport header
219 snprintf( msg->payload, 500, "Stand up and cheer from OU to Oh yea! (5)" );
221 msg = rmr_send_msg( rmc, msg );
222 errors += fail_if_nil( msg, "send_msg_ did not return a message on send " );
224 errors += fail_not_equal( msg->state, RMR_OK, "send_msg returned bad status for send that should work " );
225 errors += fail_if( errno != 0, "send_msg set errno for send that should work " );
226 v = rmr_payload_size( msg );
227 errors += fail_if( v != 2048, "send_msg did not allocate new buffer with correct size " );
228 errors += fail_if( msg->tp_state == 999, "send_msg did not set tp_state (2)" );
231 rmr_set_stimeout( NULL, 0 ); // not supported, but funciton exists, so drive away
232 rmr_set_stimeout( rmc, 20 );
233 rmr_set_stimeout( rmc, -1 );
234 rmr_set_rtimeout( NULL, 0 );
235 rmr_set_rtimeout( rmc, 20 );
236 rmr_set_rtimeout( rmc, -1 );
238 max_tries = 10; // there shouldn't be more than 10 queued at this point
239 while( (msg2 = rmr_torcv_msg( rmc, msg2, 200 )) != NULL ) {
240 if( msg2->state != RMR_OK || max_tries <= 0 ) {
244 fprintf( stderr, ">>>> len=%d state=%d (%s)\n", msg2->len, msg2->state, msg2->payload );
249 // ----- the queue load and disc cb tests should be last! -----------------------------
250 for( i = 0; i < 4000; i++ ) { // test ring drop
252 msg = rmr_alloc_msg( rmc, 2048 ); // get a buffer with a transport header
259 snprintf( msg->payload, 500, "Stand up and cheer from OU to Oh yea! msg=%d", i );
261 msg = rmr_send_msg( rmc, msg );
262 errors += fail_if_nil( msg, "send_msg_ did not return a message on send " );
265 mt_disc_cb( rmc, 0 ); // disconnect callback for coverage
266 mt_disc_cb( rmc, 100 ); // with a fd that doesn't exist
270 msg2 = rmr_rcv_msg( NULL, NULL );
271 errors += fail_if( msg2 != NULL, "rmr_rcv_msg returned msg when given nil context and msg " );
273 msg2 = rmr_rcv_msg( rmc, NULL );
274 errors += fail_if( msg2 == NULL, "rmr_rcv_msg returned nil msg when given nil msg " );
276 if( msg2->state != RMR_ERR_EMPTY ) {
277 errors += fail_not_equal( msg2->state, RMR_OK, "receive given nil message did not return msg with good state (not empty) " );
282 msg = rmr_rcv_msg( rmc, msg );
284 errors += fail_not_equal( msg->state, RMR_OK, "rmr_rcv_msg did not return an ok state " );
285 errors += fail_not_equal( msg->len, 220, "rmr_rcv_msg returned message with invalid len " );
287 errors += fail_if_nil( msg, "rmr_rcv_msg returned a nil pointer " );
290 rmr_rts_msg( NULL, NULL ); // drive for coverage
291 rmr_rts_msg( rmc, NULL );
292 errors += fail_if( errno == 0, "rmr_rts_msg did not set errno when given a nil message " );
295 msg = rmr_rts_msg( NULL, msg ); // should set state in msg
297 errors += fail_if_equal( msg->state, 0, "rmr_rts_msg did not set state when given valid message but no context " );
299 errors += fail_if_nil( msg, "rmr_rts_msg returned a nil msg when given a good one" );
303 msg = rmr_rts_msg( rmc, msg ); // return the buffer to the sender
304 errors += fail_if_nil( msg, "rmr_rts_msg did not return a message pointer " );
305 errors += fail_not_equal( msg->state, 0, "rts_msg did not return a good state (a) when expected" );
306 errors += fail_not_equal( errno, 0, "rmr_rts_msg did not reset errno (a) expected (b)" );
309 msg = rmr_call( NULL, msg );
310 errors += fail_if( msg->state == 0, "rmr_call did not set message state when given message with nil context " );
312 snprintf( msg->xaction, 17, "%015d", 16 ); // dummy transaction id (emulation generates, this should arrive after a few calls to recv)
315 em_set_rcvcount( 0 ); // reset message counter
316 em_set_rcvdelay( 1 ); // force slow msg rate during mt testing
317 msg = rmr_call( rmc, msg ); // dummy nng/nano function will sequentually add xactions and should match or '16'
318 errors += fail_if_nil( msg, "rmr_call returned a nil message on call expected to succeed " );
320 errors += fail_not_equal( msg->state, RMR_OK, "rmr_call did not properly set state on successful return " );
321 errors += fail_not_equal( errno, 0, "rmr_call did not properly set errno (a) on successful return " );
324 snprintf( wbuf, 17, "%015d", 14 ); // while waiting, the queued messages should have #14, so issue a few receives looking for it
325 for( i = 0; i < 16; i++ ) { // it should be in the first 15
326 msg = rmr_rcv_msg( rmc, msg );
328 if( strcmp( wbuf, msg->xaction ) == 0 ) { // found the queued message
331 fprintf( stderr, "<INFO> msg: %s\n", msg->xaction );
333 errors += fail_if_nil( msg, "receive returnd nil msg while looking for queued message " );
337 errors += fail_if( i >= 16, "did not find expected message on queue " );
340 msg = rmr_alloc_msg( rmc, 2048 ); // something buggered above; get a new one
344 msg = rmr_call( rmc, msg ); // make a call that we never expect a response on (nil pointer back)
345 errors += fail_not_nil( msg, "rmr_call returned a nil message on call expected not to receive a response " );
346 errors += fail_if( errno == 0, "rmr_call did not set errno on failure " );
348 rmr_free_msg( NULL ); // drive for coverage; nothing to check
349 rmr_free_msg( msg2 );
352 msg2 = rmr_torcv_msg( NULL, NULL, 10 );
353 errors += fail_not_nil( msg2, "rmr_torcv_msg returned a pointer when given nil information " );
354 msg2 = rmr_torcv_msg( rmc, NULL, 10 );
355 errors += fail_if_nil( msg2, "rmr_torcv_msg did not return a message pointer when given a nil old msg " );
357 // --- test timeout receive; our dummy epoll function will return 1 ready on first call and 0 ready (timeout emulation) on second
358 // 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.
360 for( i = 0; i < 40; i++ ) {
361 msg = rmr_torcv_msg( rmc, msg, 10 );
362 errors += fail_if_nil( msg, "torcv_msg returned nil msg when message expected " );
364 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
369 errors += fail_if( i >= 40, "torcv_msg never returned a timeout " );
372 // ---- trace things that are not a part of the mbuf_api functions and thus must be tested here -------
373 state = rmr_init_trace( NULL, 37 ); // coverage test nil context
374 errors += fail_not_equal( state, 0, "attempt to initialise trace with nil context returned non-zero state (a) " );
375 errors += fail_if_equal( errno, 0, "attempt to initialise trace with nil context did not set errno as expected " );
377 state = rmr_init_trace( rmc, 37 );
378 errors += fail_if_equal( state, 0, "attempt to set trace len in context was not successful " );
379 errors += fail_not_equal( errno, 0, "attempt to set trace len in context did not clear errno " );
381 msg = rmr_tralloc_msg( rmc, 1024, 17, "1904308620110417" );
382 errors += fail_if_nil( msg, "attempt to allocate message with trace data returned nil message " );
383 state = rmr_get_trace( msg, wbuf, 17 );
384 errors += fail_not_equal( state, 17, "len of trace data (a) returned after msg allocation was not expected size (b) " );
385 state = strcmp( wbuf, "1904308620110417" );
386 errors += fail_not_equal( state, 0, "trace data returned after tralloc was not correct " );
388 em_send_failures = 1;
389 send_n_msgs( rmc, 30 ); // send 30 messages with emulation failures
390 em_send_failures = 0;
393 ((uta_ctx_t *)rmc)->shutdown = 1;
394 rmr_close( NULL ); // drive for coverage
395 rmr_close( rmc ); // no return to check; drive for coverage
399 // --------------- phew, done ------------------------------------------------------------------------------
402 fprintf( stderr, "<INFO> all RMr API tests pass\n" );