CI: Add silent cmake SonarCloud scan
[ric-plt/lib/rmr.git] / test / si95_test.c
1 // :vi sw=4 ts=4 noet:
2 /*
3 ==================================================================================
4         Copyright (c) 2020-2021 Nokia
5         Copyright (c) 2020-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:       si95_test.c
23         Abstract:       This is the main driver to test the si95 core functions
24                                 (within rmr/src/si/src/si95).
25
26         Author:         E. Scott Daniels
27         Date:           6 March 2018
28 */
29
30 #include <stdio.h>
31 #include <stdlib.h>
32 #include <netdb.h>
33 #include <errno.h>
34 #include <string.h>
35 #include <pthread.h>
36 #include <ctype.h>
37 #include <unistd.h>
38 #include <strings.h>
39 #include <stdint.h>
40 #include <sys/epoll.h>
41 #include <semaphore.h>
42
43
44 #include <netdb.h>              // these four needed for si address tests
45 #include <stdio.h>
46 #include <ctype.h>
47 #include <netinet/in.h>
48
49 #define DEBUG 1
50
51                                                                                         // specific test tools in this directory
52 #undef NNG_UNDER_TEST                                           // NNG is NOT under test so undefine if set
53 #define NO_EMULATION 1                                          // no emulation of transport functions
54 #define NO_PRIVATE_HEADERS 1                            // no rmr_si or rmr_nng headers
55 #define NO_DUMMY_RMR 1                                          // no msg things
56
57 #include "test_support.c"                                       // things like fail_if()
58 #include "test_transport_em.c"                          // system/transport emulation (open, close, connect, etc)
59
60 #include <rmr_logging.h>
61 #include <logging.c>
62
63
64 // ------------- dummy functions to force edge cases when we can ---------------------------------------
65
66 #define SYSTEM_UNDER_TEST       1                               // for conditional code
67
68 /*
69         These are global so they can be reset for individual tests.
70 */
71 static int good_mallocs = 0;            // number of initial good malocs before failurs
72 static int bad_mallocs = 1;                     // number of failed mallocs (consecutive)
73
74 static void* test_malloc( size_t n ) {
75
76         fprintf( stderr, ">>>> test malloc: %d %d\n", good_mallocs, bad_mallocs );
77         if( good_mallocs ) {
78                 good_mallocs--;
79                 return malloc( n );
80         }
81
82         if( bad_mallocs ) {
83                 bad_mallocs--;
84                 errno = ENOMEM;
85                 return NULL;
86         }
87
88         return malloc( n );
89 }
90
91 // -----------------------------------------------------------------------------------------------------
92
93 #include <si95/siaddress.c>
94 //#include <si95/sialloc.c>
95 #include <si95/sibldpoll.c>
96 #include <si95/sicbreg.c>
97 #include <si95/sicbstat.c>
98 #include <si95/siclose.c>
99 #include <si95/siconnect.c>
100 #include <si95/siestablish.c>
101 #include <si95/sigetadd.c>
102 #include <si95/sigetname.c>
103 #include <si95/siinit.c>
104 #include <si95/silisten.c>
105 #include <si95/sinew.c>
106 #include <si95/sinewses.c>
107 #include <si95/sipoll.c>
108 //#include <si95/sircv.c>
109 #include <si95/sisend.c>
110 #include <si95/sisendt.c>
111 #include <si95/sishutdown.c>
112 #include <si95/siterm.c>
113 #include <si95/sitrash.c>
114 #define malloc test_malloc
115 #include <si95/siwait.c>
116 #undef malloc
117
118 // ---------------------------------------------------------------------
119
120 void*   si_ctx = NULL;                  // a global context might be useful
121
122 // ---------------------------------------------------------------------
123
124 /*
125         Fake callback to register.
126 */
127 static int test_cb( void* data ) {
128         return 0;
129 }
130
131 /*
132         Returns error for coverage testing of CB calls
133 */
134 static int test_cb_err( void* data ) {
135         return -1;
136 }
137
138 /*
139         Memory allocation/free related tests
140 */
141 static int memory( ) {
142         int             errors = 0;
143         void*   ptr;
144         void*   iptr;
145
146         // ---- SInew ----------------
147         ptr = SInew( 100 );                             // invalid block type should return nil
148         errors += fail_not_nil( ptr, "memory: sinew did not return nil when given a valid struct type" );
149         SItrash( 100, NULL );                           // drive trash for coverage
150
151         iptr = SInew( IOQ_BLK );
152         errors += fail_if_nil( iptr, "memory: sinew returned nil when given ioq request" );
153         SItrash(  IOQ_BLK, iptr );
154
155         ptr = SInew( TP_BLK );
156         errors += fail_if_nil( ptr, "memory: sinew returned nil when given tpblk request" );
157         if( ptr ) {
158                 iptr = SInew( IOQ_BLK );
159                 ((struct tp_blk *)ptr)->squeue = iptr;
160                 SItrash(  TP_BLK, ptr );
161         }
162
163         ptr = SInew( GI_BLK );
164         errors += fail_if_nil( ptr, "memory: sinew returned nil when given giblk request" );
165         SItrash(  GI_BLK, ptr );                // GI block cannot be trashed, ensure this (valgind will complain about a leak)
166         free( ptr );                                    // we can free GI block only in tests
167
168         fprintf( stderr, "<INFO> memory module finished with %d errors\n", errors );
169         return errors;
170 }
171
172 /*
173         Test initialisation related things
174 */
175 static int init() {
176         int             errors = 0;
177
178         si_ctx = SIinitialise( 0 );
179         errors += fail_if_nil( si_ctx, "init: siinit returned a nil pointer" );
180
181         SIclr_tflags( si_ctx, 0x00 );           // drive for coverage; no return value from these
182         SIset_tflags( si_ctx, 0x03 );
183
184         fprintf( stderr, "<INFO> init  module finished with %d errors\n", errors );
185         return errors;
186 }
187
188 static int cleanup() {
189         int errors = 0;
190
191         if( ! si_ctx ) {
192                 fprintf( stderr, "<INFO> cleanup has no context to use\n" );
193                 return 0;
194         }
195
196         fprintf( stderr, "<INFO> cleanup running\n" );
197         SIcbstat( si_ctx, SI_RET_UNREG, SI_CB_SECURITY );
198         SIcbstat( si_ctx, SI_RET_QUIT, SI_CB_SECURITY );
199
200         SItp_stats( si_ctx );           // drive for coverage only
201         SItp_stats( NULL );
202
203         SIconnect( si_ctx, "127.0.0.1:43086" ); // ensure context has a tp block to free on shutdown
204         SIshutdown( NULL );
205         SIabort( si_ctx );
206
207         // cleaning up the remaining global resources
208         struct ginfo_blk *gptr = (struct ginfo_blk*)si_ctx;
209         SItrash( TP_BLK, gptr->tplist );
210         free( gptr->tp_map );
211         free( gptr->rbuf );
212         free( gptr->cbtab );
213         free( si_ctx );
214
215         fprintf( stderr, "<INFO> cleanup  module finished with %d errors\n", errors );
216         return errors;
217 }
218
219 /*
220         Address related tests.
221 */
222 static int addr() {
223         int errors = 0;
224         int l;
225         char buf1[4096];                        // space to build buffers for xlation
226         char*   hr_addr;                        // human readable address returned
227         void* net_addr;                         // a network address block of some type
228
229 /*
230         struct sockaddr* addr;
231         addr = (struct sockaddr *) malloc( sizeof( struct sockaddr ) );
232
233         l = SIgenaddr( "    [ff02::4]:4567", PF_INET6, IPPROTO_TCP, SOCK_STREAM, &addr );
234
235         SIgenaddr( "    [ff02::4]:4567", PF_INET6, IPPROTO_TCP, SOCK_STREAM, &addr );
236 */
237
238         l = SIaddress( NULL, NULL, 0 );
239         errors += fail_if_true( l != 0, "SIaddress given two null pointers didn't return 0 len" );
240         l = SIaddress( buf1, NULL, 0 );
241         errors += fail_if_true( l != 0, "SIaddress given null dest pointer didn't return 0 len" );
242         l = SIaddress( NULL, (void *) &buf1, 0 );
243         errors += fail_if_true( l != 0, "SIaddress given null src pointer didn't return 0 len" );
244
245         net_addr = NULL;
246         snprintf( buf1, sizeof( buf1 ), "   [ff02::5:4001" );           // invalid address, drive leading space eater too
247         l = SIaddress( buf1, (void **)  &net_addr, AC_TOADDR6 );
248         errors += fail_if_true( l > 0, "to addr6 with bad addr convdersion returned valid len" );
249         free( net_addr );
250
251         snprintf( buf1, sizeof( buf1 ), "[ff02::5]:4002" );             // v6 might not be supported so failure is OK here; driving for coverage
252         l = SIaddress( buf1, &net_addr, AC_TOADDR6 );
253         if( l > 0 ) {
254                 l = SIaddress( net_addr, (void *) &hr_addr, AC_TODOT );                                         // convert the address back to hr string
255                 errors += fail_if_true( l < 1, "v6 to dot conversion failed" );
256                 errors += fail_if_nil( hr_addr, "v6 to dot conversion yields a nil pointer" );
257                 free( net_addr );
258                 free( hr_addr );
259         }
260
261         snprintf( buf1, sizeof( buf1 ), "localhost:43086" );
262         l = SIaddress( buf1, (void **) &net_addr, AC_TOADDR );
263         errors += fail_if_true( l < 1, "v4 to addr conversion failed" );
264
265         l = SIaddress( net_addr, (void *) &hr_addr, AC_TODOT );                                         // convert the address back to hr string
266         errors += fail_if_true( l < 1, "to dot convdersion failed" );
267         errors += fail_if_nil( hr_addr, "v4 to dot conversion yields a nil pointer" );
268         free( net_addr );
269         free( hr_addr );
270
271         fprintf( stderr, "<INFO> addr module finished with %d errors\n", errors );
272         return errors;
273 }
274
275 /*
276         Prep related tests. These mostly drive cases that aren't driven by "normal"
277         connect, send, receive tests (e.g. UDP branches).
278 */
279 static int prep() {
280         int             errors = 0;
281         void*   thing;                                  // the thing that should be returned
282
283         thing = SIlisten_prep( UDP_DEVICE, "localhost:1234", AF_INET );
284         errors += fail_if_nil( thing, "listen prep udp returned nil block" );
285         SItrash( TP_BLK, thing );
286
287         thing = SIlisten_prep( UDP_DEVICE, "localhost:1234", 84306 );           // this should fail
288         errors += fail_not_nil( thing, "listen prep udp returned valid block ptr for bogus family" );
289
290         thing = SIconn_prep( si_ctx, UDP_DEVICE, "localhost:1234", 84306 );             // again, expect to fail; bogus family
291         errors += fail_not_nil( thing, "conn prep udp returned valid block ptr for bogus family" );
292
293         return errors;
294 }
295
296 /*
297         Polling/waiting tests.  These are difficult at best because of the blocking
298         nature of things, not to mention needing to have real ports open etc.
299 */
300 static int poll() {
301         int errors  = 0;
302         int status;
303         struct ginfo_blk* dummy;
304
305
306         dummy = SIinitialise( 0 );                              // get one to fiddle to drive edge cases
307         dummy->flags |= GIF_SHUTDOWN;                   // shutdown edge condition
308         SIpoll( dummy, 1 );
309
310         free( dummy->tp_map );
311         free( dummy->rbuf );
312         free( dummy->cbtab );
313
314         memset( dummy, 0, sizeof( *dummy ) );   // force bad cookie check code to drive
315         SIpoll( dummy, 1 );
316
317         free (dummy );
318
319         status = SIpoll( si_ctx, 1 );
320         errors += fail_if_true( status != 0, "poll failed" );
321
322         return errors;
323 }
324
325
326 /*
327         Connection oriented tests.
328 */
329 static int conn( ) {
330         int errors = 0;
331         int state;
332         int cfd = 3;                                    // fd for close
333         char*   buf;
334
335         state = SIconnect( si_ctx, "localhost:4567" );          // driver regular connect
336         errors += fail_if_true( state < 0, "connect to low port failed" );
337
338         state = SIconnect( si_ctx, "localhost:43086" );         // drive save connect with good return code
339         errors += fail_if_true( state < 0, "connect to high port failed" );
340
341         tpem_set_addr_dup_state( 1 );                                           // force get sockket name emulation to return a duplicate address
342         state = SIconnect( si_ctx, "localhost:43086" );         // drive save connect with good return code
343         errors += fail_if_true( state >= 0, "forced dup connect did not return error" );
344
345         tpem_set_addr_dup_state( 0 );                                           // back to normal
346         tpem_set_conn_state( -1 );
347         state = SIconnect( si_ctx, "localhost:4567" );          // driver regular connect
348         errors += fail_if_true( state >= 0, "connect to low port successful when failure expected" );
349         tpem_set_conn_state( 3 );
350
351         tpem_set_sock_state( 1 );                                                       // make scoket calls fail
352         state = SIconnect( si_ctx, "localhost:4567" );          // driver regular connect
353         errors += fail_if_true( state >= 0, "connect to low port successful when socket based failure expected" );
354
355         tpem_set_sock_state( 0 );
356
357         state = SIlistener( si_ctx, TCP_DEVICE, "0.0.0.0:4567" );
358         errors += fail_if_true( state < 0, "listen failed" );
359
360         tpem_set_bind_state( 1 );
361         state = SIlistener( si_ctx, TCP_DEVICE, "0.0.0.0:4567" );
362         errors += fail_if_true( state >= 0, "listen successful when bind error set" );
363         tpem_set_bind_state( 0 );
364
365         SIbldpoll( si_ctx );            // for coverage. no return value and nothing we can check
366
367         state = SIclose( NULL, 0 );                     //coverage
368         errors += fail_if_true( state != SI_ERROR, "close given nil context returned success" );
369
370         state = SIclose( si_ctx, cfd );
371         errors += fail_if_true( state == SI_ERROR, "close given good context and good fd returned error" );
372
373         state = SIclose( si_ctx, 5000 );                                                // out of range fd
374         errors += fail_if_true( state != SI_ERROR, "close given good context and bad fd returned success" );
375
376         state = SIclose( si_ctx, TCP_LISTEN_PORT );                             // close listener
377         errors += fail_if_true( state == SI_ERROR, "close given good context and listener fd returned error" );
378
379         state = SIclose( si_ctx, UDP_PORT );                                    // close first open udp port (should not be there)
380         errors += fail_if_true( state != SI_ERROR, "close given good context and udp generic fd returned error" );
381
382         buf = SIgetname( 3 );
383         if( fail_if_true( buf == NULL, "get name failed to return a buffer" ) ) {
384                 errors++;
385         } else {
386                 errors += fail_if_true( buf[0] == 0, "get name returned buf with emtpy string" );
387                 free( buf );
388         }
389
390         buf = SIgetname( -1 );                  // invalid fd
391         errors += fail_not_nil( buf, "get name returned buf with non-emtpy string when given bad fd" );
392
393         fprintf( stderr, "<INFO> conn module finished with %d errors\n", errors );
394         return errors;
395 }
396
397 /*
398         Misc tests that just don't fit in another bucket.
399 */
400 static int misc( ) {
401         int errors = 0;
402         char    buf[1024];
403
404         SIcbreg( NULL, SI_CB_SECURITY, test_cb, NULL );         // coverage only, no return value no verification
405         SIcbreg( si_ctx, SI_CB_SECURITY, test_cb, NULL );
406
407         buf[0] = 0;
408         SIgetaddr( si_ctx, buf );
409         errors += fail_if_true( buf[0] == 0, "get address failed" );
410         fprintf( stderr, "<INFO> get address returns (%s)\n", buf );
411
412         fprintf( stderr, "<INFO> misc module finished with %d errors\n", errors );
413         return errors;
414 }
415
416
417 /*
418         New session (accept) testing.
419 */
420 static int new_sess( ) {
421         int errors = 0;
422         char    buf[1024];
423         struct tp_blk *tpptr;
424         int             status;
425
426         tpptr = SInew( TP_BLK );
427         tpptr->fd = 3;
428         tpptr->flags |= TPF_LISTENFD;
429
430         tpem_set_accept_fd( -1 );                                                                       // accept will "fail" for coverage
431         status = SInewsession( si_ctx, tpptr );
432         errors += fail_if_true( status != SI_ERROR, "newsession did not fail when accept fails" );
433
434         tpem_set_accept_fd( 5 );                                                                        // accept will return a good fd
435         SIcbreg( si_ctx, SI_CB_SECURITY, test_cb_err, NULL );           // register error and drive new session for error coverage
436         status = SInewsession( si_ctx, tpptr );
437         errors += fail_if_true( status >= 0, "newsession did failed when accept was good" );
438
439         tpem_set_accept_fd( 6 );                                                                        // accept will return a good fd
440         SIset_tflags( si_ctx, SI_TF_NODELAY | SI_TF_FASTACK );          // flip options for coverage in new sess
441         SIcbreg( si_ctx, SI_CB_CONN, test_cb, NULL );                           // drive connection for coverage
442         SIcbreg( si_ctx, SI_CB_SECURITY, test_cb, NULL );
443         status = SInewsession( si_ctx, tpptr );
444         errors += fail_if_true( status < 0, "newsession did failed when accept was good" );
445
446         free( tpptr );
447
448         fprintf( stderr, "<INFO> new_sess module finished with %d errors\n", errors );
449         return errors;
450 }
451
452 /*
453         Send tests
454 */
455 static int send_tests( ) {
456         int             errors = 0;
457         char    buf[1024];
458         int             len;
459         int             state;
460
461         len = snprintf( buf, 100, "Heaven knows I'm miserable now!" );
462
463         state = SIsendt( si_ctx, 9999, buf, len );
464         errors += fail_if_true( state >= 0, "send given fd out of range did not fail" );
465
466         state = SIsendt( si_ctx, -1, buf, len );
467         errors += fail_if_true( state >= 0, "send given neg fd did not fail" );
468
469         SIsendt( si_ctx, 6, buf, len );
470
471         tpem_set_send_err( 99 );
472         SIsendt( si_ctx, 6, buf, len );
473
474         tpem_set_send_err( 0 );
475         tpem_set_sel_blk( 1 );
476         SIsendt( si_ctx, 6, buf, len );
477
478         tpem_set_sel_blk( 0 );
479         tpem_set_selef_fd( 6 );                                         // will cause send to fail and fd6 to close
480         SIsendt( si_ctx, 6, buf, len );
481
482         return errors;
483 }
484
485
486 /*
487         Wait testing.  This is tricky because we don't have any sessions and thus it's difficult
488         to drive much of SIwait().
489 */
490 static int wait_tests() {
491         int errors = 0;
492         struct ginfo_blk* dummy;
493
494
495         dummy = SIinitialise( 0 );                              // get one to fiddle to drive edge cases
496         SIwait( dummy );                                                // malloc should "fail"
497
498         dummy->flags |= GIF_SHUTDOWN;
499         SIwait( dummy );
500
501         free( dummy->tp_map );
502         free( dummy->rbuf );
503         free( dummy->cbtab );
504
505         memset( dummy, 0, sizeof( *dummy ) );   // force bad cookie check code to drive
506         SIwait( dummy );
507
508         free( dummy );
509
510
511         SIwait( si_ctx );                                               // should drive once through the loop
512
513         return errors;
514 }
515
516 // ----------------------------------------------------------------------------------------
517
518 /*
519         Drive tests...
520 */
521 int main() {
522         int errors = 0;
523
524         rmr_set_vlevel( 5 );                    // enable all debugging
525
526         fprintf( stderr, "\n<INFO> starting SI95 tests\n" );
527
528         errors += init();
529         errors += memory();
530         errors += addr();
531         errors += prep();
532         errors += conn();
533         errors += misc();
534
535         errors += new_sess();           // should leave a "connected" session at fd == 6
536         errors += send_tests();
537
538         errors += poll();
539         errors += wait_tests();
540
541         errors += cleanup();
542
543         test_summary( errors, "SI95 tests" );
544         if( errors == 0 ) {
545                 fprintf( stderr, "<PASS> all tests were OK\n\n" );
546         } else {
547                 fprintf( stderr, "<FAIL> %d errors in SI95 core code\n\n", errors );
548         }
549
550         return !!errors;
551 }