CI: Add silent cmake SonarCloud scan
[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-2021 Nokia
5             Copyright (c) 2018-2021 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                                 Not all message/call functions can be tested here because of the
49                                 callback nature of SI.  There is a specific rcv test static module
50                                 for those tests.
51
52         Author:         E. Scott Daniels
53         Date:           5 April 2019
54 */
55
56 #include <unistd.h>
57 #include <stdio.h>
58 #include <stdlib.h>
59 #include <strings.h>
60 #include <errno.h>
61 #include <string.h>
62 #include <stdint.h>
63 #include <pthread.h>
64 #include <semaphore.h>
65
66 #include "rmr.h"
67 #include "rmr_agnostic.h"
68
69 /*
70         Driving ep counts is tricky when trying to do it as a part of the rts function, so
71         we drive that code on it's own.
72 */
73 static int test_ep_counts() {
74         int errors = 0;
75         struct endpoint ep;                     // need a dummy endpoint
76
77         memset( &ep, 0, sizeof( ep ) );
78
79         incr_ep_counts( RMR_OK, &ep );
80         errors += fail_if_false(  ep.scounts[EPSC_GOOD] == 1, "ep inc good counter had bad value" );
81
82         incr_ep_counts( RMR_ERR_RETRY, &ep );
83         errors += fail_if_false(  ep.scounts[EPSC_TRANS] == 1, "ep inc trans counter had bad value" );
84
85         incr_ep_counts( 99, &ep );                              // any non-retry/ok value
86         errors += fail_if_false(  ep.scounts[EPSC_FAIL] == 1, "ep inc fail counter had bad value" );
87
88         incr_ep_counts( RMR_OK, NULL );                 // ensure nil pointer doesn't crash us
89
90         return errors;
91 }
92
93 static int rmr_api_test( ) {
94         int             errors = 0;
95         void*   rmc;                            // route manager context
96         void*   rmc2;                           // second context for non-listener init
97         rmr_mbuf_t*     msg;                    // message buffers
98         rmr_mbuf_t*     msg2;
99         int             v = 0;                                  // some value
100         char    wbuf[128];
101         int             i;
102         void*   p;                                      // generic pointer to test return value
103         int             state;
104         int             max_tries;                      // prevent a sticking in any loop
105         uta_ctx_t* ctx;
106
107         v = rmr_ready( NULL );
108         errors += fail_if( v != 0, "rmr_ready returned true before initialisation "  );
109
110         em_set_long_hostname( 1 );
111         if( (rmc = rmr_init( "4560", 1024, FL_NOTHREAD )) == NULL ) {
112                 fail_if_nil( rmc, "rmr_init returned a nil pointer "  );
113                 return 1;
114         }
115
116         setenv( "RMR_SRC_ID", "somehost", 1 );                                                          // context should have this as source
117         if( (rmc2 = rmr_init( ":6789", 1024, FL_NOTHREAD )) == NULL ) {         // init without starting a thread
118                 errors += fail_if_nil( rmc, "rmr_init returned a nil pointer for non-threaded init "  );
119         }
120
121         fprintf( stderr, "<INFO> with RMR_SRC_ID env set, source name in context: (%s)\n", ((uta_ctx_t *) rmc2)->my_name );
122         v = strcmp( ((uta_ctx_t *) rmc2)->my_name, "somehost:6789" );
123         errors += fail_not_equal( v, 0, "source name not set from environment variable (see previous info)" );
124         free_ctx( rmc2 );                       // coverage
125
126         unsetenv( "RMR_SRC_ID" );                                                                                               // context should NOT have our artificial name
127         if( (rmc2 = rmr_init( NULL, 1024, FL_NOTHREAD )) == NULL ) {                    // drive default port selector code
128                 errors += fail_if_nil( rmc, "rmr_init returned a nil pointer when driving for default port "  );
129         }
130
131         fprintf( stderr, "<INFO> after unset of RMR_SRC_ID, source name in context: (%s)\n", ((uta_ctx_t *) rmc2)->my_name );
132         v = strcmp( ((uta_ctx_t *) rmc2)->my_name, "somehost:6789" );
133         errors += fail_if_equal( v, 0, "source name smells when removed from environment (see previous info)" );
134         free_ctx( rmc2 );                       // attempt to reduce leak check errors
135
136         v = rmr_ready( rmc );           // unknown return; not checking at the moment
137
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 "  );
140
141
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 "  );
144         if( msg ) {
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 );
148         }
149
150
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 "  );
154
155         v = rmr_payload_size( msg );
156         if( v >= 0 ) {
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 "  );
159         } else {
160                 errors += fail_if( v < 0, "rmr_payload_size returned invalid size for good message "  );
161         }
162
163
164
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 "  );
169
170         msg2 = rmr_send_msg( NULL, NULL );
171         errors += fail_not_nil( msg2, "send_msg returned msg pointer when given a nil message and context "  );
172
173         msg->state = 0;
174         msg = rmr_send_msg( NULL, msg );
175         errors += fail_if( msg->state == 0, "rmr_send_msg did not set msg state when msg given with nil context "  );
176
177         // --- sends will fail with a no endpoint error until a dummy route table is set, so we test fail case first.
178         msg->len = 100;
179         msg->mtype = 1;
180         msg->state = 999;
181         msg->tp_state = 999;
182         errno = 999;
183         snprintf( msg->payload, 100, "Stand up and cheer from OU to Oh yea! (1)" );
184
185         msg = rmr_send_msg( rmc, msg );
186         errors += fail_if_nil( msg, "send_msg_ did not return a message on send "  );
187         if( msg ) {
188                 errors += fail_not_equal( msg->state, RMR_ERR_NOENDPT, "send_msg did not return no endpoints before rtable added "  );
189                 errors += fail_if( errno == 0, "send_msg did not set errno "  );
190                 errors += fail_if( msg->tp_state == 999, "send_msg did not set tp_state (1)" );
191         }
192
193         gen_rt( rmc );          // --- after this point there is a dummy route table so send and rts calls should be ok
194
195         if( ! rmr_ready( rmc ) ) {
196                 fprintf( stderr, "\nPANIC!  rmr isn't showing ready after loading a rt table\n\n" );
197                 return errors;
198         }
199
200         state = init_mtcall( NULL );                                    // drive for coverage
201         errors += fail_not_equal( state, 0, "init_mtcall did not return false (a) when given a nil context pointer" );
202
203         rmr_free_msg( msg );
204         msg = rmr_alloc_msg( rmc, 2048 );                               // get a buffer with a transport header
205         msg->len = 500;
206         msg->mtype = 1;
207         msg->state = 999;
208         msg->tp_state = 999;
209         errno = 999;
210         snprintf( msg->payload, 500, "Stand up and cheer from OU to Oh yea! (5)" );
211
212         msg = rmr_send_msg( rmc, msg );
213         errors += fail_if_nil( msg, "send_msg_ did not return a message on send "  );
214         if( msg ) {
215                 errors += fail_not_equal( msg->state, RMR_OK, "send_msg returned bad status for send that should work "  );
216                 errors += fail_if( errno != 0, "send_msg set errno for send that should work "  );
217                 v = rmr_payload_size( msg );
218                 errors += fail_if( v != 2048, "send_msg did not allocate new buffer with correct size "  );
219                 errors += fail_if( msg->tp_state == 999, "send_msg did not set tp_state (2)" );
220         }
221
222         rmr_set_stimeout( NULL, 0 );            // not supported, but funciton exists, so drive away
223         rmr_set_stimeout( rmc, 20 );
224         rmr_set_stimeout( rmc, -1 );
225         rmr_set_rtimeout( NULL, 0 );
226         rmr_set_rtimeout( rmc, 20 );
227         rmr_set_rtimeout( rmc, -1 );
228
229         max_tries = 10;                                         // there shouldn't be more than 10 queued at this point
230         while( (msg2 = rmr_torcv_msg( rmc, msg2, 200 )) != NULL ) {
231                 if( msg2->state != RMR_OK || max_tries <= 0 ) {
232                         break;
233                 }
234
235                 fprintf( stderr, ">>>> len=%d state=%d (%s)\n", msg2->len, msg2->state, msg2->payload );
236                 max_tries--;
237         }
238
239         // ----- the queue load and disc cb tests should be last! -----------------------------
240         for( i = 0; i < 4000; i++ ) {                   // test ring drop
241                 if( msg == NULL ) {
242                         msg = rmr_alloc_msg( rmc, 2048 );                               // get a buffer with a transport header
243                 }
244                 msg->len = 500;
245                 msg->mtype = 1;
246                 msg->state = 999;
247                 msg->tp_state = 999;
248                 errno = 999;
249                 snprintf( msg->payload, 500, "Stand up and cheer from OU to Oh yea! msg=%d", i );
250
251                 msg = rmr_send_msg( rmc, msg );
252                 errors += fail_if_nil( msg, "send_msg_ did not return a message on send "  );
253         }
254
255         mt_disc_cb( rmc, 0 );                   // disconnect callback for coverage
256         mt_disc_cb( rmc, 100 );                 // with a fd that doesn't exist
257
258
259         // ---- trace things that are not a part of the mbuf_api functions and thus must be tested here -------
260         state = rmr_init_trace( NULL, 37 );                                             // coverage test nil context
261         errors += fail_not_equal( state, 0, "attempt to initialise trace with nil context returned non-zero state (a) "  );
262         errors += fail_if_equal( errno, 0, "attempt to initialise trace with nil context did not set errno as expected "  );
263
264         state = rmr_init_trace( rmc, 37 );
265         errors += fail_if_equal( state, 0, "attempt to set trace len in context was not successful "  );
266         errors += fail_not_equal( errno, 0, "attempt to set trace len in context did not clear errno "  );
267
268         msg = rmr_tralloc_msg( rmc, 1024, 17, "1904308620110417" );
269         errors += fail_if_nil( msg, "attempt to allocate message with trace data returned nil message "  );
270         state = rmr_get_trace( msg, wbuf, 17 );
271         errors += fail_not_equal( state, 17, "len of trace data (a) returned after msg allocation was not expected size (b) "  );
272         state = strcmp( wbuf, "1904308620110417" );
273         errors += fail_not_equal( state, 0, "trace data returned after tralloc was not correct "  );
274
275         em_send_failures = 1;
276         send_n_msgs( rmc, 30 );                 // send 30 messages with emulation failures
277         em_send_failures = 0;
278
279
280         ((uta_ctx_t *)rmc)->shutdown = 1;
281         rmr_close( NULL );                      // drive for coverage
282         rmr_close( rmc );                       // no return to check; drive for coverage
283
284
285         // ----- mt_rcv edge cases -------------------------------------------------------------------------------------
286         ctx = mk_dummy_ctx();
287         p = rmr_mt_rcv( NULL, msg, 0 );                         // give a valid message to cover additional lines
288         errors += fail_if_nil( p, "rmr_rt_rcv did not pointer when given a message with a nil context" );
289         if( msg ) {
290                 errors += fail_if_equal( msg->state, RMR_OK, "rmr_mt_rcv returned OK state when given nil context" );
291         }
292
293         p = rmr_mt_rcv( ctx, msg, 0 );                          // one shot receive "poll" case
294         errors += fail_if_nil( p, "mt_rcv with one shot time length did not return a pointer" );
295
296
297         // --------------- nil pointer exception checks ----------------------------------------------------------------
298         rmr_rcv_specific( NULL, NULL, "foo", 0 );
299         mt_call( NULL, NULL, 0, 1, NULL );
300         rmr_mt_call( NULL, NULL, 0, 1 );
301         rmr_set_low_latency( NULL );
302         rmr_set_fack( NULL );
303
304
305         msg2 = rmr_alloc_msg( rmc,  1024 );
306         msg2 = rmr_rcv_msg( NULL, msg2 );
307         if( msg2 != NULL ) {
308                 errors += fail_if( msg2->state == RMR_OK, "nil context check for rcv msg returned OK" );
309         }
310         msg2 = rmr_torcv_msg( NULL, msg2, 200 );
311         if( msg2 != NULL ) {
312                 errors += fail_if( msg2->state == RMR_OK, "nil context check for torcv msg returned OK" );
313         }
314
315         //  ----- thread start coverage ---------------------------------------------------------------------------
316         setenv( "RMR_WARNINGS", "1", 1 );       // force non-default branches during these tests
317         setenv( "RMR_SRC_NAMEONLY", "1", 1 );
318
319         rmr_init( ":6789", 1024, 0 );           // threaded mode with defined/default RM target
320         setenv( "RMR_RTG_SVC", "-1", 1 );       // force into static table mode
321         rmr_init( ":6789", 1024, 0 );           // threaded mode with static table
322
323
324         // ---- some things must be pushed specifically for edge cases and such ------------------------------------
325         errors += test_ep_counts();
326         init_err( "test error message", rmc, rmc2, ENOMEM );            // drive for coverage
327
328         ctx = mk_dummy_ctx();
329         ctx->river_hash = rmr_sym_alloc( 129 );
330
331         buf2mbuf( NULL, NULL, 0, 0 );                                                           // things in mt_call_si_static
332
333         state = mt_data_cb( NULL, 0, "123", 3 );
334         errors += fail_not_equal( state, 0, "mt_data_cb didn't respond correctly when ctx is nil" );
335
336         state = mt_data_cb( ctx, -1, "123", 3 );
337         errors += fail_not_equal( state, 0, "mt_data_cb didn't respond correctly when ctx is nil" );
338
339         ctx->nrivers = 1;
340         state = mt_data_cb( ctx, 23, "123", 3 );                                        // force add river to hash reference
341         errors += fail_not_equal( state, 0, "mt_data_cb didn't respond correctly when ctx is nil" );
342
343         mt_disc_cb( NULL, 0 );
344         mt_disc_cb( ctx, 128 );                                 // for a FD we know isn't there
345
346
347         p = mt_receive( NULL );
348         errors += fail_not_nil( p, "mt_receive returned non-nil pointer when given nil context" );
349
350         // --------------- phew, done ------------------------------------------------------------------------------
351
352         if( ! errors ) {
353                 fprintf( stderr, "<INFO> all RMr API tests pass\n" );
354         }
355         return errors;
356 }