1 // : vi ts=4 sw=4 noet :
3 ==================================================================================
4 Copyright (c) 2019 Nokia
5 Copyright (c) 2018-2019 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_api_static_test.c
23 Abstract: Specific tests related to the API functions in rmr_nng.c/rmr.c.
24 This should be included by a driver, but only the main RMr
25 driver and there will likely not be a specific stand alone driver
26 for just this small set of tests because of the depth of the
27 library needed to test at this level.
29 This can be used for both the nng and nanomsg outward facing
32 The message buffer specific API tests are in a different static
33 module. API functions tested here are:
49 Author: E. Scott Daniels
61 #include <semaphore.h>
64 #include "rmr_agnostic.h"
67 Send a 'burst' of messages to drive some send retry failures to increase RMr coverage
68 by handling the retry caee.
70 static void send_n_msgs( void* ctx, int n ) {
71 rmr_mbuf_t* msg; // message buffers
74 msg = rmr_alloc_msg( ctx, 1024 );
79 for( i = 0; i < n; i++ ) {
80 //fprintf( stderr, "mass send\n" );
85 msg = rmr_send_msg( ctx, msg );
90 Refresh or allocate a message with some default values
92 static rmr_mbuf_t* fresh_msg( void* ctx, rmr_mbuf_t* msg ) {
94 msg = rmr_alloc_msg( ctx, 2048 );
105 static int rmr_api_test( ) {
107 void* rmc; // route manager context
108 void* rmc2; // second context for non-listener init
109 rmr_mbuf_t* msg; // message buffers
111 int v = 0; // some value
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 " );
173 // this is only supported in nng, so behavour is different depending on the underlying library being tested
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 v = rmr_get_rcvfd( NULL );
180 errors += fail_if( v >= 0, "rmr_get_rcvfd returned a valid file descriptor when given nil context " );
181 v = rmr_get_rcvfd( rmc );
182 errors += fail_if( v >= 0, "rmr_get_rcvfd returned a valid file descriptor (not supported in nanomsg)" );
185 msg2 = rmr_send_msg( NULL, NULL ); // drive for coverage
186 errors += fail_not_nil( msg2, "send_msg returned msg pointer when given a nil message and context " );
189 msg = rmr_send_msg( NULL, msg );
190 errors += fail_if( msg->state == 0, "rmr_send_msg did not set msg state when msg given with nil context " );
192 // --- sends will fail with a no endpoint error until a dummy route table is set, so we test fail case first.
198 msg = rmr_send_msg( rmc, msg );
199 errors += fail_if_nil( msg, "send_msg_ did not return a message on send " );
201 errors += fail_not_equal( msg->state, RMR_ERR_NOENDPT, "send_msg did not return no endpoints before rtable added " );
202 errors += fail_if( errno == 0, "send_msg did not set errno " );
203 errors += fail_if( msg->tp_state == 999, "send_msg did not set tp_state (1)" );
206 gen_rt( rmc ); // --- after this point there is a dummy route table so send and rts calls should be ok
213 msg = rmr_send_msg( rmc, msg );
214 errors += fail_if_nil( msg, "send_msg_ did not return a message on send " );
216 errors += fail_not_equal( msg->state, RMR_OK, "send_msg returned bad status for send that should work " );
217 errors += fail_if( errno != 0, "send_msg set errno for send that should work " );
218 v = rmr_payload_size( msg );
219 errors += fail_if( v != 2048, "send_msg did not allocate new buffer with correct size " );
220 errors += fail_if( msg->tp_state == 999, "send_msg did not set tp_state (2)" );
223 rmr_set_stimeout( NULL, 0 );
224 rmr_set_stimeout( rmc, 20 );
225 rmr_set_stimeout( rmc, -1 );
226 rmr_set_rtimeout( NULL, 0 );
227 rmr_set_rtimeout( rmc, 20 );
228 rmr_set_rtimeout( rmc, -1 );
230 msg2 = rmr_rcv_msg( NULL, NULL );
231 errors += fail_if( msg2 != NULL, "rmr_rcv_msg returned msg when given nil context and msg " );
233 msg2 = rmr_rcv_msg( rmc, NULL );
234 errors += fail_if( msg2 == NULL, "rmr_rcv_msg returned nil msg when given nil msg " );
236 if( msg2->state != RMR_ERR_EMPTY ) {
237 errors += fail_not_equal( msg2->state, RMR_OK, "receive given nil message did not return msg with good state (not empty) " );
242 msg = rmr_rcv_msg( rmc, msg );
244 errors += fail_not_equal( msg->state, RMR_OK, "rmr_rcv_msg did not return an ok state " );
245 errors += fail_not_equal( msg->len, 220, "rmr_rcv_msg returned message with invalid len " );
247 errors += fail_if_nil( msg, "rmr_rcv_msg returned a nil pointer " );
250 rmr_rts_msg( NULL, NULL ); // drive for coverage
251 rmr_rts_msg( rmc, NULL );
252 errors += fail_if( errno == 0, "rmr_rts_msg did not set errno when given a nil message " );
255 msg = rmr_rts_msg( NULL, msg ); // should set state in msg
257 errors += fail_if_equal( msg->state, 0, "rmr_rts_msg did not set state when given valid message but no context " );
259 errors += fail_if_nil( msg, "rmr_rts_msg returned a nil msg when given a good one" );
263 msg = rmr_rts_msg( rmc, msg ); // return the buffer to the sender
264 errors += fail_if_nil( msg, "rmr_rts_msg did not return a message pointer " );
265 errors += fail_not_equal( msg->state, 0, "rts_msg did not return a good state (a) when expected" );
266 errors += fail_not_equal( errno, 0, "rmr_rts_msg did not reset errno (a) expected (b)" );
271 msg = rmr_call( NULL, msg );
272 errors += fail_if( msg->state == 0, "rmr_call did not set message state when given message with nil context " );
274 snprintf( msg->xaction, 17, "%015d", 16 ); // dummy transaction id (emulation generates, this should arrive after a few calls to recv)
277 msg = rmr_call( rmc, msg ); // dummy nng/nano function will sequentually add xactions and should match or '16'
278 errors += fail_if_nil( msg, "rmr_call returned a nil message on call expected to succeed " );
280 errors += fail_not_equal( msg->state, RMR_OK, "rmr_call did not properly set state on successful return " );
281 errors += fail_not_equal( errno, 0, "rmr_call did not properly set errno (a) on successful return " );
284 snprintf( wbuf, 17, "%015d", 14 ); // while waiting, the queued messages should have #14, so issue a few receives looking for it
285 for( i = 0; i < 16; i++ ) { // it should be in the first 15
286 msg = rmr_rcv_msg( rmc, msg );
288 if( strcmp( wbuf, msg->xaction ) == 0 ) { // found the queued message
291 fprintf( stderr, "<INFO> msg: %s\n", msg->xaction );
293 errors += fail_if_nil( msg, "receive returnd nil msg while looking for queued message " );
297 errors += fail_if( i >= 16, "did not find expected message on queue " );
300 msg = rmr_alloc_msg( rmc, 2048 ); // something buggered above; get a new one
304 msg = rmr_call( rmc, msg ); // make a call that we never expect a response on (nil pointer back)
305 errors += fail_not_nil( msg, "rmr_call returned a nil message on call expected not to receive a response " );
306 errors += fail_if( errno == 0, "rmr_call did not set errno on failure " );
308 rmr_free_msg( NULL ); // drive for coverage; nothing to check
309 rmr_free_msg( msg2 );
312 msg2 = rmr_torcv_msg( NULL, NULL, 10 );
313 errors += fail_not_nil( msg2, "rmr_torcv_msg returned a pointer when given nil information " );
314 msg2 = rmr_torcv_msg( rmc, NULL, 10 );
315 errors += fail_if_nil( msg2, "rmr_torcv_msg did not return a message pointer when given a nil old msg " );
317 // --- test timeout receive; our dummy epoll function will return 1 ready on first call and 0 ready (timeout emulation) on second
318 // 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.
320 for( i = 0; i < 40; i++ ) {
321 msg = rmr_torcv_msg( rmc, msg, 10 );
322 errors += fail_if_nil( msg, "torcv_msg returned nil msg when message expected " );
324 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
329 errors += fail_if( i >= 40, "torcv_msg never returned a timeout " );
332 // ---- trace things that are not a part of the mbuf_api functions and thus must be tested here -------
333 state = rmr_init_trace( NULL, 37 ); // coverage test nil context
334 errors += fail_not_equal( state, 0, "attempt to initialise trace with nil context returned non-zero state (a) " );
335 errors += fail_if_equal( errno, 0, "attempt to initialise trace with nil context did not set errno as expected " );
337 state = rmr_init_trace( rmc, 37 );
338 errors += fail_if_equal( state, 0, "attempt to set trace len in context was not successful " );
339 errors += fail_not_equal( errno, 0, "attempt to set trace len in context did not clear errno " );
341 msg = rmr_tralloc_msg( rmc, 1024, 17, "1904308620110417" );
342 errors += fail_if_nil( msg, "attempt to allocate message with trace data returned nil message " );
343 state = rmr_get_trace( msg, wbuf, 17 );
344 errors += fail_not_equal( state, 17, "len of trace data (a) returned after msg allocation was not expected size (b) " );
345 state = strcmp( wbuf, "1904308620110417" );
346 errors += fail_not_equal( state, 0, "trace data returned after tralloc was not correct " );
348 em_send_failures = 1;
349 send_n_msgs( rmc, 30 ); // send 30 messages with emulation failures
350 em_send_failures = 0;
353 ((uta_ctx_t *)rmc)->shutdown = 1;
354 rmr_close( NULL ); // drive for coverage
355 rmr_close( rmc ); // no return to check; drive for coverage
358 // -- allocate a new context for mt-call and drive that stuff -----------------------------------------
360 msg = fresh_msg( rmc, msg ); // ensure we have one with known contents
363 msg = rmr_mt_call( rmc, msg, 3, 10 ); // drive when not in mt setup
365 errors += fail_not_equal( msg->state, RMR_ERR_NOTSUPP, "rmr_mt_call did not set not supported error when not mt initialised" );
367 errors += fail_if_nil( msg, "rmr_mt_call returned nil pointer when not mt initialised" );
369 msg = fresh_msg( rmc, msg );
371 msg = rmr_mt_rcv( rmc, msg, 10 ); // gen not supported error if ctx not set for mt
373 errors += fail_not_equal( msg->state, RMR_ERR_NOTSUPP, "rmr_mt_rcv did not return not supported state when mt not initialised" );
375 errors += fail_if_nil( msg, "nil pointer from rmr_mt_rcv when mt not initialised\n" );
377 msg = fresh_msg( rmc, msg );
381 msg = rmr_mt_call( rmc, msg, 1000, 10 ); // thread id out of range
382 errors += fail_if_equal( msg->state, 0, "rmr_mt_call did not set an error when given an invalid call-id" );
384 errors += fail_if_nil( msg, "rmr_mt_call returned a nil pointer when given an invalid call-id" );
386 msg = fresh_msg( rmc, msg );
388 state = init_mtcall( NULL ); // drive for coverage
389 errors += fail_not_equal( state, 0, "init_mtcall did not return false (a) when given a nil context pointer" );
392 if( (rmc = rmr_init( NULL, 1024, FL_NOTHREAD | RMRFL_MTCALL )) == NULL ) { // drive multi-call setup code without rtc thread
393 errors += fail_if_nil( rmc, "rmr_init returned a nil pointer when driving for mt-call setup " );
396 gen_rt( rmc ); // must attach a route table so sends succeed
398 fprintf( stderr, "<INFO> enabling mt messages\n" );
399 em_set_rcvdelay( 1 ); // force slow msg rate during mt testing
400 em_set_mtc_msgs( 1 ); // emulated nngrcv will now generate messages with call-id and call flag
403 msg = rmr_mt_call( NULL, msg, 3, 10 ); // should timeout
405 errors += fail_if( msg->state == 0, "rmr_mt_call did not set message state when given message with nil context " );
407 msg = fresh_msg( rmc, msg );
409 fprintf( stderr, "<INFO> invoking mt_call with timout == 2999\n" );
410 msg = rmr_mt_call( rmc, msg, 2, 2999 ); // long timeout to drive time building code, should receive
412 if( msg->state != RMR_OK ) {
413 fprintf( stderr, "<INFO> rmr_mt_call returned error in mbuf: %d\n", msg->state );
415 errors += fail_not_nil( msg, "rmr_mt_call did not return a nil pointer on read timeout" );
418 msg = fresh_msg( rmc, msg );
420 msg = rmr_mt_rcv( NULL, NULL, 10 );
421 errors += fail_not_nil( msg, "rmr_mt_rcv returned a non-nil message when given nil message and nil context" );
423 fprintf( stderr, "<INFO> invoking mt_rcv with timout == 2999\n" );
424 msg = fresh_msg( rmc, msg );
425 msg = rmr_mt_rcv( rmc, msg, 2999 );
427 errors += fail_if_nil( msg, "rmr_mt_rcv returned a nil message when given valid message and timeout of 29999" );
429 msg = fresh_msg( rmc, msg );
431 msg = rmr_mt_rcv( rmc, msg, -1 );
433 errors += fail_if_nil( msg, "rmr_mt_rcv returned a nil message when given valid message unlimited timeout" );
435 msg = fresh_msg( rmc, msg );
437 fprintf( stderr, "<INFO> waiting 20.0 seconds for a known call xaction to arrive (%ld)\n", time( NULL ) );
438 snprintf( msg->xaction, 17, "%015d", 5 ); // we'll reset receive counter before calling mt_call so this will arrive again
439 em_set_rcvcount( 0 );
440 msg = rmr_mt_call( rmc, msg, 2, 15000 ); // we need about 10s to get the message with the 'slow rate'
442 errors += fail_not_equal( msg->state, RMR_OK, "mt_call with known xaction id bad state (a)" );
444 errors += fail_if_nil( msg, "mt_call with known xaction id returned nil message" );
446 fprintf( stderr, "<INFO> time check: %ld\n", time( NULL ) );
449 em_set_mtc_msgs( 0 ); // turn off
450 em_set_rcvdelay( 0 ); // full speed receive rate
451 ((uta_ctx_t *)rmc)->shutdown = 1; // force the mt-reciver attached to the context to stop
453 em_set_rcvdelay( 0 ); // let the receive loop spin w/o receives so we drive warning code about queue full
455 em_set_rcvdelay( 1 ); // restore slow receive pace for any later tests
459 // --------------- phew, done ------------------------------------------------------------------------------
462 fprintf( stderr, "<INFO> all RMr API tests pass\n" );