Remove nanomsg support from app test scripts
[ric-plt/lib/rmr.git] / test / rmr_nng_api_static_test.c
1 // : vi ts=4 sw=4 noet :
2 /*
3 ==================================================================================
4             Copyright (c) 2019 Nokia
5             Copyright (c) 2018-2019 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_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.
28
29                                 This can be used for both the nng and nanomsg outward facing
30                                 RMr API functions.
31
32                                 The message buffer specific API tests are in a different static
33                                 module.  API functions tested here are:
34                                          rmr_close
35                                          rmr_get_rcvfd
36                                          rmr_ready
37                                          rmr_init
38                                          rmr_set_rtimeout
39                                          rmr_set_stimeout
40                                          rmr_rcv_specific
41                                          rmr_torcv_msg
42                                          rmr_rcv_msg
43                                          rmr_call
44                                          rmr_rts_msg
45                                          rmr_send_msg
46                                          rmr_mtosend_msg
47                                          rmr_free_msg
48
49         Author:         E. Scott Daniels
50         Date:           5 April 2019
51 */
52
53 #include <unistd.h>
54 #include <stdio.h>
55 #include <stdlib.h>
56 #include <strings.h>
57 #include <errno.h>
58 #include <string.h>
59 #include <stdint.h>
60 #include <pthread.h>
61 #include <semaphore.h>
62
63 #include "rmr.h"
64 #include "rmr_agnostic.h"
65
66 /*
67         Send a 'burst' of messages to drive some send retry failures to increase RMr coverage
68         by handling the retry caee.
69 */
70 static void send_n_msgs( void* ctx, int n ) {
71         rmr_mbuf_t*     msg;                    // message buffers
72         int i;
73
74         msg = rmr_alloc_msg( ctx,  1024 );
75         if( ! msg ) {
76                 return;
77         }
78
79         for( i = 0; i < n; i++ ) {
80                 //fprintf( stderr, "mass send\n" );
81                 msg->len = 100;
82                 msg->mtype = 1;
83                 msg->state = 999;
84                 errno = 999;
85                 msg = rmr_send_msg( ctx, msg );
86         }
87 }
88
89 /*
90         Refresh or allocate a message with some default values
91 */
92 static rmr_mbuf_t* fresh_msg( void* ctx, rmr_mbuf_t* msg ) {
93         if( ! msg )  {
94                 msg = rmr_alloc_msg( ctx, 2048 );
95         }
96
97         msg->mtype = 0;
98         msg->sub_id = -1;
99         msg->state = 0;
100         msg->len = 100;
101
102         return msg;
103 }
104
105 static int rmr_api_test( ) {
106         int             errors = 0;
107         void*   rmc;                            // route manager context
108         void*   rmc2;                           // second context for non-listener init
109         rmr_mbuf_t*     msg;                    // message buffers
110         rmr_mbuf_t*     msg2;
111         int             v = 0;                                  // some value
112         char    wbuf[128];
113         int             i;
114         int             state;
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         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 "  );
127         }
128
129         free_ctx( rmc2 );                       // coverage
130
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 "  );
133         }
134
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 #ifdef EMULATE_NNG
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 "  );
169 #else
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)"  );
174 #endif
175
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 "  );
178
179         msg->state = 0;
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 "  );
182
183         // --- sends will fail with a no endpoint error until a dummy route table is set, so we test fail case first.
184         msg->len = 100;
185         msg->mtype = 1;
186         msg->state = 999;
187         msg->tp_state = 999;
188         errno = 999;
189         msg = rmr_send_msg( rmc, msg );
190         errors += fail_if_nil( msg, "send_msg_ did not return a message on send "  );
191         if( msg ) {
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)" );
195         }
196
197         gen_rt( rmc );          // --- after this point there is a dummy route table so send and rts calls should be ok
198
199         msg->len = 100;
200         msg->mtype = 1;
201         msg->state = 999;
202         msg->tp_state = 999;
203         errno = 999;
204         msg = rmr_send_msg( rmc, msg );
205         errors += fail_if_nil( msg, "send_msg_ did not return a message on send "  );
206         if( msg ) {
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)" );
212         }
213
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 );
220
221         msg2 = rmr_rcv_msg( NULL, NULL );
222         errors += fail_if( msg2 != NULL, "rmr_rcv_msg returned msg when given nil context and msg "  );
223
224         msg2 = rmr_rcv_msg( rmc, NULL );
225         errors += fail_if( msg2 == NULL, "rmr_rcv_msg returned nil msg when given nil msg "  );
226         if( msg2 ) {
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) "  );
229                 }
230         }
231
232
233         msg = rmr_rcv_msg( rmc, msg );
234         if( 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 "  );
237         } else {
238                 errors += fail_if_nil( msg, "rmr_rcv_msg returned a nil pointer "  );
239         }
240
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 "  );
244
245         msg->state = 0;
246         msg = rmr_rts_msg( NULL, msg );                 // should set state in msg
247         if( msg ) {
248                 errors += fail_if_equal( msg->state, 0, "rmr_rts_msg did not set state when given valid message but no context "  );
249         } else {
250                 errors += fail_if_nil( msg,  "rmr_rts_msg returned a nil msg when given a good one" );
251         }
252
253
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)"  );
258
259
260
261         msg->state = 0;
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 "  );
264
265         snprintf( msg->xaction, 17, "%015d", 16 );              // dummy transaction id (emulation generates, this should arrive after a few calls to recv)
266         msg->mtype = 0;
267         msg->sub_id = -1;
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 "  );
270         if( msg ) {
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 "  );
273         }
274
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 );
278                 if( msg ) {
279                         if( strcmp( wbuf, msg->xaction ) == 0 ) {               // found the queued message
280                                 break;
281                         }
282                         fprintf( stderr, "<INFO> msg: %s\n", msg->xaction );
283                 } else {
284                         errors += fail_if_nil( msg, "receive returnd nil msg while looking for queued message "  );
285                 }
286         }
287
288         errors += fail_if( i >= 16, "did not find expected message on queue "  );
289
290         if( ! msg ) {
291                 msg = rmr_alloc_msg( rmc, 2048 );                               // something buggered above; get a new one
292         }
293         msg->mtype = 0;
294         msg->sub_id = -1;
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 "  );
298
299         rmr_free_msg( NULL );                   // drive for coverage; nothing to check
300         rmr_free_msg( msg2 );
301
302
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 "  );
307
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.
310         msg = NULL;
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 "  );
314                 if( msg ) {
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
316                                 break;
317                         }
318                 }
319         }
320         errors += fail_if( i >= 40, "torcv_msg never returned a timeout "  );
321
322
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 "  );
327
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 "  );
331
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 "  );
338
339         em_send_failures = 1;
340         send_n_msgs( rmc, 30 );                 // send 30 messages with emulation failures
341         em_send_failures = 0;
342
343
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
347
348
349         // -- allocate a new context for mt-call and drive that stuff -----------------------------------------
350 #ifdef EMULATE_NNG
351         msg = fresh_msg( rmc, msg );                                                    // ensure we have one with known contents
352
353         msg->state = 0;
354         msg = rmr_mt_call( rmc, msg, 3, 10 );                                                   // drive when not in mt setup
355         if( msg ) {
356                 errors += fail_not_equal( msg->state, RMR_ERR_NOTSUPP, "rmr_mt_call did not set not supported error when not mt initialised" );
357         } else {
358                 errors += fail_if_nil( msg, "rmr_mt_call returned nil pointer when not mt initialised" );
359         }
360         msg = fresh_msg( rmc, msg );
361
362         msg = rmr_mt_rcv( rmc, msg, 10 );                                                               // gen not supported error if ctx not set for mt
363         if( msg ) {
364                 errors += fail_not_equal( msg->state, RMR_ERR_NOTSUPP, "rmr_mt_rcv did not return not supported state when mt not initialised" );
365         } else {
366                 errors += fail_if_nil( msg, "nil pointer from rmr_mt_rcv when mt not initialised\n" );
367         }
368         msg = fresh_msg( rmc, msg );
369
370         msg->state = 0;
371         if( 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" );
374         } else {
375                 errors += fail_if_nil( msg, "rmr_mt_call returned a nil pointer when given an invalid call-id" );
376         }
377         msg = fresh_msg( rmc, msg );
378
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" );
381
382
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 "  );
385         }
386
387         gen_rt( rmc );                                                                  // must attach a route table so sends succeed
388
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
392
393         msg->state = 0;
394         msg = rmr_mt_call( NULL, msg, 3, 10 );                  // should timeout
395         if( msg ) {
396                 errors += fail_if( msg->state == 0, "rmr_mt_call did not set message state when given message with nil context "  );
397         }
398         msg = fresh_msg( rmc, msg );
399
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
402         if( msg ) {
403                 if( msg->state != RMR_OK ) {
404                         fprintf( stderr, "<INFO> rmr_mt_call returned error in mbuf: %d\n", msg->state );
405                 } else {
406                         errors += fail_not_nil( msg, "rmr_mt_call did not return a nil pointer on read timeout" );
407                 }
408         }
409         msg = fresh_msg( rmc, msg );
410
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" );
413
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 );
417         if( !msg ) {
418                 errors += fail_if_nil( msg, "rmr_mt_rcv returned a nil message when given valid message and timeout of 29999" );
419         }
420         msg = fresh_msg( rmc, msg );
421
422         msg = rmr_mt_rcv( rmc, msg, -1 );
423         if( !msg ) {
424                 errors += fail_if_nil( msg, "rmr_mt_rcv returned a nil message when given valid message unlimited timeout" );
425         }
426         msg = fresh_msg( rmc, msg );
427
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'
432         if( msg ) {
433                 errors += fail_not_equal( msg->state, RMR_OK, "mt_call with known xaction id bad state (a)" );
434         } else {
435                 errors += fail_if_nil( msg, "mt_call with known xaction id returned nil message" );
436         }
437         fprintf( stderr, "<INFO> time check: %ld\n", time( NULL ) );
438                 
439
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
443 #endif
444
445
446         // --------------- phew, done ------------------------------------------------------------------------------
447
448         if( ! errors ) {
449                 fprintf( stderr, "<INFO> all RMr API tests pass\n" );
450         }
451         return !!errors;
452 }