Eliminate the SI receive buffer length requirement
[ric-plt/lib/rmr.git] / test / rmr_si_api_static_test.c
1 // : vi ts=4 sw=4 noet :
2 /*
3 ==================================================================================
4             Copyright (c) 2019-2020 Nokia
5             Copyright (c) 2018-2020 AT&T Intellectual Property.
6
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
10
11            http://www.apache.org/licenses/LICENSE-2.0
12
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 ==================================================================================
19 */
20
21 /*
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.
26
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
29                                 different).
30
31                                 The message buffer specific API tests are in a different static
32                                 module.  API functions tested here are:
33                                          rmr_close
34                                          rmr_get_rcvfd
35                                          rmr_ready
36                                          rmr_init
37                                          rmr_set_rtimeout
38                                          rmr_set_stimeout
39                                          rmr_rcv_specific
40                                          rmr_torcv_msg
41                                          rmr_rcv_msg
42                                          rmr_call
43                                          rmr_rts_msg
44                                          rmr_send_msg
45                                          rmr_mtosend_msg
46                                          rmr_free_msg
47
48         Author:         E. Scott Daniels
49         Date:           5 April 2019
50 */
51
52 #include <unistd.h>
53 #include <stdio.h>
54 #include <stdlib.h>
55 #include <strings.h>
56 #include <errno.h>
57 #include <string.h>
58 #include <stdint.h>
59 #include <pthread.h>
60 #include <semaphore.h>
61
62 #include "rmr.h"
63 #include "rmr_agnostic.h"
64
65 /*
66         Send a 'burst' of messages to drive some send retry failures to increase RMr coverage
67         by handling the retry caee.
68 */
69 static void send_n_msgs( void* ctx, int n ) {
70         rmr_mbuf_t*     msg;                    // message buffers
71         int i;
72
73         msg = rmr_alloc_msg( ctx,  1024 );
74         if( ! msg ) {
75                 return;
76         }
77
78         for( i = 0; i < n; i++ ) {
79                 //fprintf( stderr, "mass send\n" );
80                 msg->len = 100;
81                 msg->mtype = 1;
82                 msg->state = 999;
83                 errno = 999;
84                 msg = rmr_send_msg( ctx, msg );
85         }
86 }
87
88 /*
89         Refresh or allocate a message with some default values
90 */
91 static rmr_mbuf_t* fresh_msg( void* ctx, rmr_mbuf_t* msg ) {
92         if( ! msg )  {
93                 msg = rmr_alloc_msg( ctx, 2048 );
94         }
95
96         msg->mtype = 0;
97         msg->sub_id = -1;
98         msg->state = 0;
99         msg->len = 100;
100
101         return msg;
102 }
103
104 static int rmr_api_test( ) {
105         int             errors = 0;
106         void*   rmc;                            // route manager context
107         void*   rmc2;                           // second context for non-listener init
108         rmr_mbuf_t*     msg;                    // message buffers
109         rmr_mbuf_t*     msg2;
110         int             v = 0;                                  // some value
111         char    wbuf[128];
112         int             i;
113         int             state;
114         int             max_tries;                      // prevent a sticking in any loop
115
116         v = rmr_ready( NULL );
117         errors += fail_if( v != 0, "rmr_ready returned true before initialisation "  );
118
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 "  );
122                 return 1;
123         }
124
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 "  );
128         }
129
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
134         
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 "  );
138         }
139
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
144
145         v = rmr_ready( rmc );           // unknown return; not checking at the moment
146
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 "  );
149
150         
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 "  );
153         if( msg ) {
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 );
157         }
158
159
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 "  );
163
164         v = rmr_payload_size( msg );
165         if( v >= 0 ) {
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 "  );
168         } else {
169                 errors += fail_if( v < 0, "rmr_payload_size returned invalid size for good message "  );
170         }
171
172
173
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 "  );
178
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 "  );
181
182         msg->state = 0;
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 "  );
185
186         // --- sends will fail with a no endpoint error until a dummy route table is set, so we test fail case first.
187         msg->len = 100;
188         msg->mtype = 1;
189         msg->state = 999;
190         msg->tp_state = 999;
191         errno = 999;
192         snprintf( msg->payload, 100, "Stand up and cheer from OU to Oh yea! (1)" );
193
194         msg = rmr_send_msg( rmc, msg );
195         errors += fail_if_nil( msg, "send_msg_ did not return a message on send "  );
196         if( msg ) {
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)" );
200         }
201
202         gen_rt( rmc );          // --- after this point there is a dummy route table so send and rts calls should be ok
203
204         if( ! rmr_ready( rmc ) ) {
205                 fprintf( stderr, "\nPANIC!  rmr isn't showing ready after loading a rt table\n\n" );
206                 return errors;
207         }
208
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" );
211
212         rmr_free_msg( msg );
213         msg = rmr_alloc_msg( rmc, 2048 );                               // get a buffer with a transport header
214         msg->len = 500;
215         msg->mtype = 1;
216         msg->state = 999;
217         msg->tp_state = 999;
218         errno = 999;
219         snprintf( msg->payload, 500, "Stand up and cheer from OU to Oh yea! (5)" );
220
221         msg = rmr_send_msg( rmc, msg );
222         errors += fail_if_nil( msg, "send_msg_ did not return a message on send "  );
223         if( msg ) {
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)" );
229         }
230
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 );
237
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 ) {
241                         break;
242                 }
243
244                 fprintf( stderr, ">>>> len=%d state=%d (%s)\n", msg2->len, msg2->state, msg2->payload );
245                 max_tries--;
246         }
247
248
249         // ----- the queue load and disc cb tests should be last! -----------------------------
250         for( i = 0; i < 4000; i++ ) {                   // test ring drop 
251                 if( msg == NULL ) {
252                         msg = rmr_alloc_msg( rmc, 2048 );                               // get a buffer with a transport header
253                 }
254                 msg->len = 500;
255                 msg->mtype = 1;
256                 msg->state = 999;
257                 msg->tp_state = 999;
258                 errno = 999;
259                 snprintf( msg->payload, 500, "Stand up and cheer from OU to Oh yea! msg=%d", i );
260
261                 msg = rmr_send_msg( rmc, msg );
262                 errors += fail_if_nil( msg, "send_msg_ did not return a message on send "  );
263         }
264
265         mt_disc_cb( rmc, 0 );                   // disconnect callback for coverage
266         mt_disc_cb( rmc, 100 );                 // with a fd that doesn't exist
267
268 return errors;
269
270         msg2 = rmr_rcv_msg( NULL, NULL );
271         errors += fail_if( msg2 != NULL, "rmr_rcv_msg returned msg when given nil context and msg "  );
272
273         msg2 = rmr_rcv_msg( rmc, NULL );
274         errors += fail_if( msg2 == NULL, "rmr_rcv_msg returned nil msg when given nil msg "  );
275         if( msg2 ) {
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) "  );
278                 }
279         }
280
281
282         msg = rmr_rcv_msg( rmc, msg );
283         if( 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 "  );
286         } else {
287                 errors += fail_if_nil( msg, "rmr_rcv_msg returned a nil pointer "  );
288         }
289
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 "  );
293
294         msg->state = 0;
295         msg = rmr_rts_msg( NULL, msg );                 // should set state in msg
296         if( msg ) {
297                 errors += fail_if_equal( msg->state, 0, "rmr_rts_msg did not set state when given valid message but no context "  );
298         } else {
299                 errors += fail_if_nil( msg,  "rmr_rts_msg returned a nil msg when given a good one" );
300         }
301
302
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)"  );
307
308         msg->state = 0;
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 "  );
311
312         snprintf( msg->xaction, 17, "%015d", 16 );              // dummy transaction id (emulation generates, this should arrive after a few calls to recv)
313         msg->mtype = 0;
314         msg->sub_id = -1;
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 "  );
319         if( msg ) {
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 "  );
322         }
323
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 );
327                 if( msg ) {
328                         if( strcmp( wbuf, msg->xaction ) == 0 ) {               // found the queued message
329                                 break;
330                         }
331                         fprintf( stderr, "<INFO> msg: %s\n", msg->xaction );
332                 } else {
333                         errors += fail_if_nil( msg, "receive returnd nil msg while looking for queued message "  );
334                 }
335         }
336
337         errors += fail_if( i >= 16, "did not find expected message on queue "  );
338
339         if( ! msg ) {
340                 msg = rmr_alloc_msg( rmc, 2048 );                               // something buggered above; get a new one
341         }
342         msg->mtype = 0;
343         msg->sub_id = -1;
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 "  );
347
348         rmr_free_msg( NULL );                   // drive for coverage; nothing to check
349         rmr_free_msg( msg2 );
350
351
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 "  );
356
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.
359         msg = NULL;
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 "  );
363                 if( msg ) {
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
365                                 break;
366                         }
367                 }
368         }
369         errors += fail_if( i >= 40, "torcv_msg never returned a timeout "  );
370
371
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 "  );
376
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 "  );
380
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 "  );
387
388         em_send_failures = 1;
389         send_n_msgs( rmc, 30 );                 // send 30 messages with emulation failures
390         em_send_failures = 0;
391
392
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
396
397
398
399         // --------------- phew, done ------------------------------------------------------------------------------
400
401         if( ! errors ) {
402                 fprintf( stderr, "<INFO> all RMr API tests pass\n" );
403         }
404         return !!errors;
405 }