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 if( (rmc2 = rmr_init( ":6789", 1024, FL_NOTHREAD )) == NULL ) { // init without starting a thread
126 errors += fail_if_nil( rmc, "rmr_init returned a nil pointer for non-threaded init " );
129 free_ctx( rmc2 ); // coverage
131 if( (rmc2 = rmr_init( NULL, 1024, FL_NOTHREAD )) == NULL ) { // drive default port selector code
132 errors += fail_if_nil( rmc, "rmr_init returned a nil pointer when driving for default port " );
136 v = rmr_ready( rmc ); // unknown return; not checking at the moment
138 msg = rmr_alloc_msg( NULL, 1024 ); // should return nil pointer
139 errors += fail_not_nil( msg, "rmr_alloc_msg didn't return nil when given nil context " );
142 msg = rmr_alloc_msg( rmc, 2048 ); // allocate larger than default size given on init
143 errors += fail_if_nil( msg, "rmr_alloc_msg returned nil msg pointer " );
145 rmr_get_srcip( msg, wbuf );
146 errors += fail_if_equal( 0, strlen( wbuf ), "rmr_get_srcip did not did not return string with length (b) after alloc_msg" );
147 fprintf( stderr, "<INFO> ip: %s\n", wbuf );
151 v = rmr_payload_size( NULL );
152 errors += fail_if( v >= 0, "rmr_payload_size returned valid size for nil message " );
153 errors += fail_if( errno == 0, "rmr_payload_size did not set errno on failure " );
155 v = rmr_payload_size( msg );
157 errors += fail_not_equal( v, 2048, "rmr_payload_size returned invalid size (a) instead of expected size (b) " );
158 errors += fail_if( errno != 0, "rmr_payload_size did not clear errno on success " );
160 errors += fail_if( v < 0, "rmr_payload_size returned invalid size for good message " );
164 // this is only supported in nng, so behavour is different depending on the underlying library being tested
165 v = rmr_get_rcvfd( NULL );
166 errors += fail_if( v >= 0, "rmr_get_rcvfd returned a valid file descriptor when given nil context " );
167 v = rmr_get_rcvfd( rmc );
168 errors += fail_if( v < 0, "rmr_get_rcvfd did not return a valid file descriptor " );
170 v = rmr_get_rcvfd( NULL );
171 errors += fail_if( v >= 0, "rmr_get_rcvfd returned a valid file descriptor when given nil context " );
172 v = rmr_get_rcvfd( rmc );
173 errors += fail_if( v >= 0, "rmr_get_rcvfd returned a valid file descriptor (not supported in nanomsg)" );
176 msg2 = rmr_send_msg( NULL, NULL ); // drive for coverage
177 errors += fail_not_nil( msg2, "send_msg returned msg pointer when given a nil message and context " );
180 msg = rmr_send_msg( NULL, msg );
181 errors += fail_if( msg->state == 0, "rmr_send_msg did not set msg state when msg given with nil context " );
183 // --- sends will fail with a no endpoint error until a dummy route table is set, so we test fail case first.
189 msg = rmr_send_msg( rmc, msg );
190 errors += fail_if_nil( msg, "send_msg_ did not return a message on send " );
192 errors += fail_not_equal( msg->state, RMR_ERR_NOENDPT, "send_msg did not return no endpoints before rtable added " );
193 errors += fail_if( errno == 0, "send_msg did not set errno " );
194 errors += fail_if( msg->tp_state == 999, "send_msg did not set tp_state (1)" );
197 gen_rt( rmc ); // --- after this point there is a dummy route table so send and rts calls should be ok
204 msg = rmr_send_msg( rmc, msg );
205 errors += fail_if_nil( msg, "send_msg_ did not return a message on send " );
207 errors += fail_not_equal( msg->state, RMR_OK, "send_msg returned bad status for send that should work " );
208 errors += fail_if( errno != 0, "send_msg set errno for send that should work " );
209 v = rmr_payload_size( msg );
210 errors += fail_if( v != 2048, "send_msg did not allocate new buffer with correct size " );
211 errors += fail_if( msg->tp_state == 999, "send_msg did not set tp_state (2)" );
214 rmr_set_stimeout( NULL, 0 );
215 rmr_set_stimeout( rmc, 20 );
216 rmr_set_stimeout( rmc, -1 );
217 rmr_set_rtimeout( NULL, 0 );
218 rmr_set_rtimeout( rmc, 20 );
219 rmr_set_rtimeout( rmc, -1 );
221 msg2 = rmr_rcv_msg( NULL, NULL );
222 errors += fail_if( msg2 != NULL, "rmr_rcv_msg returned msg when given nil context and msg " );
224 msg2 = rmr_rcv_msg( rmc, NULL );
225 errors += fail_if( msg2 == NULL, "rmr_rcv_msg returned nil msg when given nil msg " );
227 if( msg2->state != RMR_ERR_EMPTY ) {
228 errors += fail_not_equal( msg2->state, RMR_OK, "receive given nil message did not return msg with good state (not empty) " );
233 msg = rmr_rcv_msg( rmc, msg );
235 errors += fail_not_equal( msg->state, RMR_OK, "rmr_rcv_msg did not return an ok state " );
236 errors += fail_not_equal( msg->len, 220, "rmr_rcv_msg returned message with invalid len " );
238 errors += fail_if_nil( msg, "rmr_rcv_msg returned a nil pointer " );
241 rmr_rts_msg( NULL, NULL ); // drive for coverage
242 rmr_rts_msg( rmc, NULL );
243 errors += fail_if( errno == 0, "rmr_rts_msg did not set errno when given a nil message " );
246 msg = rmr_rts_msg( NULL, msg ); // should set state in msg
248 errors += fail_if_equal( msg->state, 0, "rmr_rts_msg did not set state when given valid message but no context " );
250 errors += fail_if_nil( msg, "rmr_rts_msg returned a nil msg when given a good one" );
254 msg = rmr_rts_msg( rmc, msg ); // return the buffer to the sender
255 errors += fail_if_nil( msg, "rmr_rts_msg did not return a message pointer " );
256 errors += fail_not_equal( msg->state, 0, "rts_msg did not return a good state (a) when expected" );
257 errors += fail_not_equal( errno, 0, "rmr_rts_msg did not reset errno (a) expected (b)" );
262 msg = rmr_call( NULL, msg );
263 errors += fail_if( msg->state == 0, "rmr_call did not set message state when given message with nil context " );
265 snprintf( msg->xaction, 17, "%015d", 16 ); // dummy transaction id (emulation generates, this should arrive after a few calls to recv)
268 msg = rmr_call( rmc, msg ); // dummy nng/nano function will sequentually add xactions and should match or '16'
269 errors += fail_if_nil( msg, "rmr_call returned a nil message on call expected to succeed " );
271 errors += fail_not_equal( msg->state, RMR_OK, "rmr_call did not properly set state on successful return " );
272 errors += fail_not_equal( errno, 0, "rmr_call did not properly set errno (a) on successful return " );
275 snprintf( wbuf, 17, "%015d", 14 ); // while waiting, the queued messages should have #14, so issue a few receives looking for it
276 for( i = 0; i < 16; i++ ) { // it should be in the first 15
277 msg = rmr_rcv_msg( rmc, msg );
279 if( strcmp( wbuf, msg->xaction ) == 0 ) { // found the queued message
282 fprintf( stderr, "<INFO> msg: %s\n", msg->xaction );
284 errors += fail_if_nil( msg, "receive returnd nil msg while looking for queued message " );
288 errors += fail_if( i >= 16, "did not find expected message on queue " );
291 msg = rmr_alloc_msg( rmc, 2048 ); // something buggered above; get a new one
295 msg = rmr_call( rmc, msg ); // make a call that we never expect a response on (nil pointer back)
296 errors += fail_not_nil( msg, "rmr_call returned a nil message on call expected not to receive a response " );
297 errors += fail_if( errno == 0, "rmr_call did not set errno on failure " );
299 rmr_free_msg( NULL ); // drive for coverage; nothing to check
300 rmr_free_msg( msg2 );
303 msg2 = rmr_torcv_msg( NULL, NULL, 10 );
304 errors += fail_not_nil( msg2, "rmr_torcv_msg returned a pointer when given nil information " );
305 msg2 = rmr_torcv_msg( rmc, NULL, 10 );
306 errors += fail_if_nil( msg2, "rmr_torcv_msg did not return a message pointer when given a nil old msg " );
308 // --- test timeout receive; our dummy epoll function will return 1 ready on first call and 0 ready (timeout emulation) on second
309 // 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.
311 for( i = 0; i < 40; i++ ) {
312 msg = rmr_torcv_msg( rmc, msg, 10 );
313 errors += fail_if_nil( msg, "torcv_msg returned nil msg when message expected " );
315 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
320 errors += fail_if( i >= 40, "torcv_msg never returned a timeout " );
323 // ---- trace things that are not a part of the mbuf_api functions and thus must be tested here -------
324 state = rmr_init_trace( NULL, 37 ); // coverage test nil context
325 errors += fail_not_equal( state, 0, "attempt to initialise trace with nil context returned non-zero state (a) " );
326 errors += fail_if_equal( errno, 0, "attempt to initialise trace with nil context did not set errno as expected " );
328 state = rmr_init_trace( rmc, 37 );
329 errors += fail_if_equal( state, 0, "attempt to set trace len in context was not successful " );
330 errors += fail_not_equal( errno, 0, "attempt to set trace len in context did not clear errno " );
332 msg = rmr_tralloc_msg( rmc, 1024, 17, "1904308620110417" );
333 errors += fail_if_nil( msg, "attempt to allocate message with trace data returned nil message " );
334 state = rmr_get_trace( msg, wbuf, 17 );
335 errors += fail_not_equal( state, 17, "len of trace data (a) returned after msg allocation was not expected size (b) " );
336 state = strcmp( wbuf, "1904308620110417" );
337 errors += fail_not_equal( state, 0, "trace data returned after tralloc was not correct " );
339 em_send_failures = 1;
340 send_n_msgs( rmc, 30 ); // send 30 messages with emulation failures
341 em_send_failures = 0;
344 ((uta_ctx_t *)rmc)->shutdown = 1;
345 rmr_close( NULL ); // drive for coverage
346 rmr_close( rmc ); // no return to check; drive for coverage
349 // -- allocate a new context for mt-call and drive that stuff -----------------------------------------
351 msg = fresh_msg( rmc, msg ); // ensure we have one with known contents
354 msg = rmr_mt_call( rmc, msg, 3, 10 ); // drive when not in mt setup
356 errors += fail_not_equal( msg->state, RMR_ERR_NOTSUPP, "rmr_mt_call did not set not supported error when not mt initialised" );
358 errors += fail_if_nil( msg, "rmr_mt_call returned nil pointer when not mt initialised" );
360 msg = fresh_msg( rmc, msg );
362 msg = rmr_mt_rcv( rmc, msg, 10 ); // gen not supported error if ctx not set for mt
364 errors += fail_not_equal( msg->state, RMR_ERR_NOTSUPP, "rmr_mt_rcv did not return not supported state when mt not initialised" );
366 errors += fail_if_nil( msg, "nil pointer from rmr_mt_rcv when mt not initialised\n" );
368 msg = fresh_msg( rmc, msg );
372 msg = rmr_mt_call( rmc, msg, 1000, 10 ); // thread id out of range
373 errors += fail_if_equal( msg->state, 0, "rmr_mt_call did not set an error when given an invalid call-id" );
375 errors += fail_if_nil( msg, "rmr_mt_call returned a nil pointer when given an invalid call-id" );
377 msg = fresh_msg( rmc, msg );
379 state = init_mtcall( NULL ); // drive for coverage
380 errors += fail_not_equal( state, 0, "init_mtcall did not return false (a) when given a nil context pointer" );
383 if( (rmc = rmr_init( NULL, 1024, FL_NOTHREAD | RMRFL_MTCALL )) == NULL ) { // drive multi-call setup code without rtc thread
384 errors += fail_if_nil( rmc, "rmr_init returned a nil pointer when driving for mt-call setup " );
387 gen_rt( rmc ); // must attach a route table so sends succeed
389 fprintf( stderr, "<INFO> enabling mt messages\n" );
390 em_set_rcvdelay( 1 ); // force slow msg rate during mt testing
391 em_set_mtc_msgs( 1 ); // emulated nngrcv will now generate messages with call-id and call flag
394 msg = rmr_mt_call( NULL, msg, 3, 10 ); // should timeout
396 errors += fail_if( msg->state == 0, "rmr_mt_call did not set message state when given message with nil context " );
398 msg = fresh_msg( rmc, msg );
400 fprintf( stderr, "<INFO> invoking mt_call with timout == 2999\n" );
401 msg = rmr_mt_call( rmc, msg, 2, 2999 ); // long timeout to drive time building code, should receive
403 if( msg->state != RMR_OK ) {
404 fprintf( stderr, "<INFO> rmr_mt_call returned error in mbuf: %d\n", msg->state );
406 errors += fail_not_nil( msg, "rmr_mt_call did not return a nil pointer on read timeout" );
409 msg = fresh_msg( rmc, msg );
411 msg = rmr_mt_rcv( NULL, NULL, 10 );
412 errors += fail_not_nil( msg, "rmr_mt_rcv returned a non-nil message when given nil message and nil context" );
414 fprintf( stderr, "<INFO> invoking mt_rcv with timout == 2999\n" );
415 msg = fresh_msg( rmc, msg );
416 msg = rmr_mt_rcv( rmc, msg, 2999 );
418 errors += fail_if_nil( msg, "rmr_mt_rcv returned a nil message when given valid message and timeout of 29999" );
420 msg = fresh_msg( rmc, msg );
422 msg = rmr_mt_rcv( rmc, msg, -1 );
424 errors += fail_if_nil( msg, "rmr_mt_rcv returned a nil message when given valid message unlimited timeout" );
426 msg = fresh_msg( rmc, msg );
428 fprintf( stderr, "<INFO> waiting 20.0 seconds for a known call xaction to arrive (%ld)\n", time( NULL ) );
429 snprintf( msg->xaction, 17, "%015d", 5 ); // we'll reset receive counter before calling mt_call so this will arrive again
430 em_set_rcvcount( 0 );
431 msg = rmr_mt_call( rmc, msg, 2, 15000 ); // we need about 10s to get the message with the 'slow rate'
433 errors += fail_not_equal( msg->state, RMR_OK, "mt_call with known xaction id bad state (a)" );
435 errors += fail_if_nil( msg, "mt_call with known xaction id returned nil message" );
437 fprintf( stderr, "<INFO> time check: %ld\n", time( NULL ) );
440 em_set_mtc_msgs( 0 ); // turn off
441 em_set_rcvdelay( 0 ); // full speed receive rate
442 ((uta_ctx_t *)rmc)->shutdown = 1; // force the mt-reciver attached to the context to stop
446 // --------------- phew, done ------------------------------------------------------------------------------
449 fprintf( stderr, "<INFO> all RMr API tests pass\n" );