Correct bug identified in static analysis
[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                                 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         int             state;
103         int             max_tries;                      // prevent a sticking in any loop
104
105         v = rmr_ready( NULL );
106         errors += fail_if( v != 0, "rmr_ready returned true before initialisation "  );
107
108         em_set_long_hostname( 1 );
109         if( (rmc = rmr_init( "4560", 1024, FL_NOTHREAD )) == NULL ) {
110                 fail_if_nil( rmc, "rmr_init returned a nil pointer "  );
111                 return 1;
112         }
113
114         setenv( "RMR_SRC_ID", "somehost", 1 );                                                          // context should have this as source
115         if( (rmc2 = rmr_init( ":6789", 1024, FL_NOTHREAD )) == NULL ) {         // init without starting a thread
116                 errors += fail_if_nil( rmc, "rmr_init returned a nil pointer for non-threaded init "  );
117         }
118
119         fprintf( stderr, "<INFO> with RMR_SRC_ID env set, source name in context: (%s)\n", ((uta_ctx_t *) rmc2)->my_name );
120         v = strcmp( ((uta_ctx_t *) rmc2)->my_name, "somehost:6789" );
121         errors += fail_not_equal( v, 0, "source name not set from environment variable (see previous info)" );
122         free_ctx( rmc2 );                       // coverage
123
124         unsetenv( "RMR_SRC_ID" );                                                                                               // context should NOT have our artificial name
125         if( (rmc2 = rmr_init( NULL, 1024, FL_NOTHREAD )) == NULL ) {                    // drive default port selector code
126                 errors += fail_if_nil( rmc, "rmr_init returned a nil pointer when driving for default port "  );
127         }
128
129         fprintf( stderr, "<INFO> after unset of RMR_SRC_ID, source name in context: (%s)\n", ((uta_ctx_t *) rmc2)->my_name );
130         v = strcmp( ((uta_ctx_t *) rmc2)->my_name, "somehost:6789" );
131         errors += fail_if_equal( v, 0, "source name smells when removed from environment (see previous info)" );
132         free_ctx( rmc2 );                       // attempt to reduce leak check errors
133
134         v = rmr_ready( rmc );           // unknown return; not checking at the moment
135
136         msg = rmr_alloc_msg( NULL,  1024 );                                                                     // should return nil pointer
137         errors += fail_not_nil( msg, "rmr_alloc_msg didn't return nil when given nil context "  );
138
139
140         msg = rmr_alloc_msg( rmc, 2048 );                               // allocate larger than default size given on init
141         errors += fail_if_nil( msg, "rmr_alloc_msg returned nil msg pointer "  );
142         if( msg ) {
143                 rmr_get_srcip( msg, wbuf );
144                 errors += fail_if_equal( 0, strlen( wbuf ), "rmr_get_srcip did not did not return string with length (b) after alloc_msg" );
145                 fprintf( stderr, "<INFO> ip: %s\n", wbuf );
146         }
147
148
149         v = rmr_payload_size( NULL );
150         errors += fail_if( v >= 0, "rmr_payload_size returned valid size for nil message "  );
151         errors += fail_if( errno == 0, "rmr_payload_size did not set errno on failure "  );
152
153         v = rmr_payload_size( msg );
154         if( v >= 0 ) {
155                 errors += fail_not_equal( v, 2048, "rmr_payload_size returned invalid size (a) instead of expected size (b) "  );
156                 errors += fail_if( errno != 0, "rmr_payload_size did not clear errno on success "  );
157         } else {
158                 errors += fail_if( v < 0, "rmr_payload_size returned invalid size for good message "  );
159         }
160
161
162
163         v = rmr_get_rcvfd( NULL );
164         errors += fail_if( v >= 0, "rmr_get_rcvfd returned a valid file descriptor when given nil context "  );
165         v = rmr_get_rcvfd( rmc );
166         errors += fail_if( v < 0, "rmr_get_rcvfd did not return a valid file descriptor "  );
167
168         msg2 = rmr_send_msg( NULL, NULL );
169         errors += fail_not_nil( msg2, "send_msg returned msg pointer when given a nil message and context "  );
170
171         msg->state = 0;
172         msg = rmr_send_msg( NULL, msg );
173         errors += fail_if( msg->state == 0, "rmr_send_msg did not set msg state when msg given with nil context "  );
174
175         // --- sends will fail with a no endpoint error until a dummy route table is set, so we test fail case first.
176         msg->len = 100;
177         msg->mtype = 1;
178         msg->state = 999;
179         msg->tp_state = 999;
180         errno = 999;
181         snprintf( msg->payload, 100, "Stand up and cheer from OU to Oh yea! (1)" );
182
183         msg = rmr_send_msg( rmc, msg );
184         errors += fail_if_nil( msg, "send_msg_ did not return a message on send "  );
185         if( msg ) {
186                 errors += fail_not_equal( msg->state, RMR_ERR_NOENDPT, "send_msg did not return no endpoints before rtable added "  );
187                 errors += fail_if( errno == 0, "send_msg did not set errno "  );
188                 errors += fail_if( msg->tp_state == 999, "send_msg did not set tp_state (1)" );
189         }
190
191         gen_rt( rmc );          // --- after this point there is a dummy route table so send and rts calls should be ok
192
193         if( ! rmr_ready( rmc ) ) {
194                 fprintf( stderr, "\nPANIC!  rmr isn't showing ready after loading a rt table\n\n" );
195                 return errors;
196         }
197
198         state = init_mtcall( NULL );                                    // drive for coverage
199         errors += fail_not_equal( state, 0, "init_mtcall did not return false (a) when given a nil context pointer" );
200
201         rmr_free_msg( msg );
202         msg = rmr_alloc_msg( rmc, 2048 );                               // get a buffer with a transport header
203         msg->len = 500;
204         msg->mtype = 1;
205         msg->state = 999;
206         msg->tp_state = 999;
207         errno = 999;
208         snprintf( msg->payload, 500, "Stand up and cheer from OU to Oh yea! (5)" );
209
210         msg = rmr_send_msg( rmc, msg );
211         errors += fail_if_nil( msg, "send_msg_ did not return a message on send "  );
212         if( msg ) {
213                 errors += fail_not_equal( msg->state, RMR_OK, "send_msg returned bad status for send that should work "  );
214                 errors += fail_if( errno != 0, "send_msg set errno for send that should work "  );
215                 v = rmr_payload_size( msg );
216                 errors += fail_if( v != 2048, "send_msg did not allocate new buffer with correct size "  );
217                 errors += fail_if( msg->tp_state == 999, "send_msg did not set tp_state (2)" );
218         }
219
220         rmr_set_stimeout( NULL, 0 );            // not supported, but funciton exists, so drive away
221         rmr_set_stimeout( rmc, 20 );
222         rmr_set_stimeout( rmc, -1 );
223         rmr_set_rtimeout( NULL, 0 );
224         rmr_set_rtimeout( rmc, 20 );
225         rmr_set_rtimeout( rmc, -1 );
226
227         max_tries = 10;                                         // there shouldn't be more than 10 queued at this point
228         while( (msg2 = rmr_torcv_msg( rmc, msg2, 200 )) != NULL ) {
229                 if( msg2->state != RMR_OK || max_tries <= 0 ) {
230                         break;
231                 }
232
233                 fprintf( stderr, ">>>> len=%d state=%d (%s)\n", msg2->len, msg2->state, msg2->payload );
234                 max_tries--;
235         }
236
237         // ----- the queue load and disc cb tests should be last! -----------------------------
238         for( i = 0; i < 4000; i++ ) {                   // test ring drop
239                 if( msg == NULL ) {
240                         msg = rmr_alloc_msg( rmc, 2048 );                               // get a buffer with a transport header
241                 }
242                 msg->len = 500;
243                 msg->mtype = 1;
244                 msg->state = 999;
245                 msg->tp_state = 999;
246                 errno = 999;
247                 snprintf( msg->payload, 500, "Stand up and cheer from OU to Oh yea! msg=%d", i );
248
249                 msg = rmr_send_msg( rmc, msg );
250                 errors += fail_if_nil( msg, "send_msg_ did not return a message on send "  );
251         }
252
253         mt_disc_cb( rmc, 0 );                   // disconnect callback for coverage
254         mt_disc_cb( rmc, 100 );                 // with a fd that doesn't exist
255
256
257         // ---- trace things that are not a part of the mbuf_api functions and thus must be tested here -------
258         state = rmr_init_trace( NULL, 37 );                                             // coverage test nil context
259         errors += fail_not_equal( state, 0, "attempt to initialise trace with nil context returned non-zero state (a) "  );
260         errors += fail_if_equal( errno, 0, "attempt to initialise trace with nil context did not set errno as expected "  );
261
262         state = rmr_init_trace( rmc, 37 );
263         errors += fail_if_equal( state, 0, "attempt to set trace len in context was not successful "  );
264         errors += fail_not_equal( errno, 0, "attempt to set trace len in context did not clear errno "  );
265
266         msg = rmr_tralloc_msg( rmc, 1024, 17, "1904308620110417" );
267         errors += fail_if_nil( msg, "attempt to allocate message with trace data returned nil message "  );
268         state = rmr_get_trace( msg, wbuf, 17 );
269         errors += fail_not_equal( state, 17, "len of trace data (a) returned after msg allocation was not expected size (b) "  );
270         state = strcmp( wbuf, "1904308620110417" );
271         errors += fail_not_equal( state, 0, "trace data returned after tralloc was not correct "  );
272
273         em_send_failures = 1;
274         send_n_msgs( rmc, 30 );                 // send 30 messages with emulation failures
275         em_send_failures = 0;
276
277
278         ((uta_ctx_t *)rmc)->shutdown = 1;
279         rmr_close( NULL );                      // drive for coverage
280         rmr_close( rmc );                       // no return to check; drive for coverage
281
282
283         // --------------- nil pointer exception checks
284         rmr_rcv_specific( NULL, NULL, "foo", 0 );
285         rmr_mt_rcv( NULL, NULL, 0 );
286         mt_call( NULL, NULL, 0, 1, NULL );
287         rmr_mt_call( NULL, NULL, 0, 1 );
288         rmr_set_low_latency( NULL );
289         rmr_set_fack( NULL );
290
291
292         msg2 = rmr_alloc_msg( rmc,  1024 );
293         msg2 = rmr_rcv_msg( NULL, msg2 );
294         if( msg2 != NULL ) {
295                 errors += fail_if( msg2->state == RMR_OK, "nil context check for rcv msg returned OK" );
296         }
297         msg2 = rmr_torcv_msg( NULL, msg2, 200 );
298         if( msg2 != NULL ) {
299                 errors += fail_if( msg2->state == RMR_OK, "nil context check for torcv msg returned OK" );
300         }
301
302         //  ----- thread start coverage ---------------------------------------------------------------------------
303         setenv( "RMR_WARNINGS", "1", 1 );       // force non-default branches during these tests
304         setenv( "RMR_SRC_NAMEONLY", "1", 1 );
305
306         rmr_init( ":6789", 1024, 0 );           // threaded mode with defined/default RM target
307         setenv( "RMR_RTG_SVC", "-1", 1 );       // force into static table mode
308         rmr_init( ":6789", 1024, 0 );           // threaded mode with static table
309
310
311         // ---- some things must be pushed specifically for edge cases and such ------------------------------------
312         errors += test_ep_counts();
313         init_err( "test error message", rmc, rmc2, ENOMEM );            // drive for coverage
314
315         // --------------- phew, done ------------------------------------------------------------------------------
316
317         if( ! errors ) {
318                 fprintf( stderr, "<INFO> all RMr API tests pass\n" );
319         }
320         return !!errors;
321 }