Fix rmr_rpobe command line bug; add test coverage
[ric-plt/lib/rmr.git] / test / si95_test.c
1 // :vi sw=4 ts=4 noet:
2 /*
3 ==================================================================================
4         Copyright (c) 2020 Nokia
5         Copyright (c) 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:       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 <errno.h>
36 #include <pthread.h>
37 #include <ctype.h>
38
39 #include <netdb.h>              // these four needed for si address tests
40 #include <stdio.h>
41 #include <ctype.h>
42 #include <netinet/in.h>
43
44
45
46 #include <unistd.h>
47 #include <stdio.h>
48 #include <stdlib.h>
49 #include <strings.h>
50 #include <errno.h>
51 #include <string.h>
52 #include <stdint.h>
53 #include <ctype.h>
54 #include <sys/epoll.h>
55 #include <pthread.h>
56 #include <semaphore.h>
57
58 #define DEBUG 1
59
60                                                                                         // specific test tools in this directory
61 #undef NNG_UNDER_TEST                                           // NNG is NOT under test so undefine if set
62 #define NO_EMULATION 1                                          // no emulation of transport functions
63 #define NO_PRIVATE_HEADERS 1                            // no rmr_si or rmr_nng headers
64 #define NO_DUMMY_RMR 1                                          // no msg things
65
66 #include "test_support.c"                                       // things like fail_if()
67 #include "test_transport_em.c"                          // system/transport emulation (open, close, connect, etc)
68
69 /*
70 #include "rmr.h"                                        // things the users see
71 #include "rmr_symtab.h"
72 #include "rmr_agnostic.h"                       // transport agnostic header
73 */
74 #include <rmr_logging.h>
75 #include <logging.c>
76
77 #include <si95/siaddress.c>
78 //#include <si95/sialloc.c>
79 #include <si95/sibldpoll.c>
80 #include <si95/sicbreg.c>
81 #include <si95/sicbstat.c>
82 #include <si95/siclose.c>
83 #include <si95/siconnect.c>
84 #include <si95/siestablish.c>
85 #include <si95/sigetadd.c>
86 #include <si95/sigetname.c>
87 #include <si95/siinit.c>
88 #include <si95/silisten.c>
89 #include <si95/sinew.c>
90 #include <si95/sinewses.c>
91 //#include <si95/sipoll.c>
92 //#include <si95/sircv.c>
93 //#include <si95/sisend.c>
94 #include <si95/sisendt.c>
95 #include <si95/sishutdown.c>
96 #include <si95/siterm.c>
97 #include <si95/sitrash.c>
98 //#include <si95/siwait.c>
99
100 // ---------------------------------------------------------------------
101
102 void*   si_ctx = NULL;                  // a global context might be useful
103
104 // ---------------------------------------------------------------------
105
106 /*
107         Fake callback to register.
108 */
109 static int test_cb( void* data ) {
110         return 0;
111 }
112
113 /*
114         Returns error for coverage testing of CB calls
115 */
116 static int test_cb_err( void* data ) {
117         return -1;
118 }
119
120 /*
121         Memory allocation/free related tests
122 */
123 static int memory( ) {
124         int             errors = 0;
125         void*   ptr;
126         void*   iptr;
127
128         // ---- SInew ----------------
129         ptr = SInew( 100 );                             // invalid block type should return nil
130         errors += fail_not_nil( ptr, "memory: sinew did not return nil when given a valid struct type" );
131         SItrash( 100, NULL );                           // drive trash for coverage
132
133         iptr = SInew( IOQ_BLK );
134         errors += fail_if_nil( iptr, "memory: sinew returned nil when given ioq request" );
135         SItrash(  IOQ_BLK, iptr );
136
137         ptr = SInew( TP_BLK );
138         errors += fail_if_nil( ptr, "memory: sinew returned nil when given tpblk request" );
139         if( ptr ) {
140                 iptr = SInew( IOQ_BLK );
141                 ((struct tp_blk *)ptr)->squeue = iptr;
142                 SItrash(  TP_BLK, ptr );
143         }
144
145         ptr = SInew( GI_BLK );
146         errors += fail_if_nil( ptr, "memory: sinew returned nil when given giblk request" );
147         SItrash(  GI_BLK, ptr );                // GI block cannot be trashed, ensure this (valgind will complain about a leak)
148
149         fprintf( stderr, "<INFO> memory module finished with %d errors\n", errors );
150         return errors;
151 }
152
153 /*
154         Test initialisation related things
155 */
156 static int init() {
157         int             errors = 0;
158
159         si_ctx = SIinitialise( 0 );
160         errors += fail_if_nil( si_ctx, "init: siinit returned a nil pointer" );
161
162         SIclr_tflags( si_ctx, 0x00 );           // drive for coverage; no return value from these
163         SIset_tflags( si_ctx, 0x03 );
164
165         fprintf( stderr, "<INFO> init  module finished with %d errors\n", errors );
166         return errors;
167 }
168
169 static int cleanup() {
170         int errors = 0;
171
172         if( ! si_ctx ) {
173                 fprintf( stderr, "<INFO> cleanup has no context to use\n" );
174                 return 0;
175         }
176
177         fprintf( stderr, "<INFO> cleanup running\n" );
178         SIcbstat( si_ctx, SI_RET_UNREG, SI_CB_SECURITY );
179         SIcbstat( si_ctx, SI_RET_QUIT, SI_CB_SECURITY );
180
181         SItp_stats( si_ctx );           // drive for coverage only
182         SItp_stats( NULL );
183
184         SIconnect( si_ctx, "localhost:43086" ); // ensure context has a tp block to free on shutdown
185         SIshutdown( NULL );
186         SIabort( si_ctx );
187
188
189         fprintf( stderr, "<INFO> cleanup  module finished with %d errors\n", errors );
190         return errors;
191 }
192
193 /*
194         Address related tests.
195 */
196 static int addr() {
197         int errors = 0;
198         int l;
199         struct sockaddr* addr;
200         char buf1[4096];
201         char buf2[4096];
202         char* dest;
203
204         addr = (struct sockaddr *) malloc( sizeof( struct sockaddr ) );
205 /*
206         l = SIgenaddr( "    [ff02::4]:4567", PF_INET6, IPPROTO_TCP, SOCK_STREAM, &addr );
207
208         SIgenaddr( "    [ff02::4]:4567", PF_INET6, IPPROTO_TCP, SOCK_STREAM, &addr );
209 */
210
211         dest = NULL;
212         snprintf( buf1, sizeof( buf1 ), "   [ff02::5:4001" );           // invalid address, drive leading space eater too
213         l = SIaddress( buf1, (void **)  &dest, AC_TOADDR6 );
214         errors += fail_if_true( l > 0, "to addr6 with bad addr convdersion returned valid len" );
215
216         snprintf( buf1, sizeof( buf1 ), "[ff02::5]:4002" );             // v6 might not be supported so failure is OK here; driving for coverage
217         l=SIaddress( buf1, (void **) &dest, AC_TOADDR6 );
218
219         snprintf( buf1, sizeof( buf1 ), "localhost:43086" );
220         l = SIaddress( buf1, (void **) &dest, AC_TOADDR );
221         errors += fail_if_true( l < 1, "to addr convdersion failed" );
222
223         snprintf( buf1, sizeof( buf1 ), "localhost:4004" );
224         l = SIaddress( buf1, (void **) &dest, AC_TODOT );
225         errors += fail_if_true( l < 1, "to dot convdersion failed" );
226
227         fprintf( stderr, "<INFO> addr module finished with %d errors\n", errors );
228         return errors;
229 }
230
231
232 /*
233         Connection oriented tests.
234 */
235 static int conn( ) {
236         int errors = 0;
237         int state;
238         int cfd = 3;                                    // fd for close
239         char*   buf;
240
241         state = SIconnect( si_ctx, "localhost:4567" );          // driver regular connect
242         errors += fail_if_true( state < 0, "connect to low port failed" );
243
244         state = SIconnect( si_ctx, "localhost:43086" );         // drive save connect with good return code
245         errors += fail_if_true( state < 0, "connect to high port failed" );
246
247         tpem_set_addr_dup_state( 1 );                                           // force get sockket name emulation to return a duplicate address
248         state = SIconnect( si_ctx, "localhost:43086" );         // drive save connect with good return code
249         errors += fail_if_true( state >= 0, "forced dup connect did not return error" );
250
251         tpem_set_addr_dup_state( 0 );                                           // back to normal
252         tpem_set_conn_state( 1 );
253         state = SIconnect( si_ctx, "localhost:4567" );          // driver regular connect
254         errors += fail_if_true( state >= 0, "connect to low port successful when failure expected" );
255
256         tpem_set_sock_state( 1 );                                                       // make scoket calls fail
257         state = SIconnect( si_ctx, "localhost:4567" );          // driver regular connect
258         errors += fail_if_true( state >= 0, "connect to low port successful when socket based failure expected" );
259
260         tpem_set_sock_state( 0 );
261
262         state = SIlistener( si_ctx, TCP_DEVICE, "0.0.0.0:4567" );
263         errors += fail_if_true( state < 0, "listen failed" );
264
265         tpem_set_bind_state( 1 );
266         state = SIlistener( si_ctx, TCP_DEVICE, "0.0.0.0:4567" );
267         errors += fail_if_true( state >= 0, "listen successful when bind error set" );
268         tpem_set_bind_state( 0 );
269
270         SIbldpoll( si_ctx );            // for coverage. no return value and nothing we can check
271
272         state = SIclose( NULL, 0 );                     //coverage
273         errors += fail_if_true( state != SI_ERROR, "close given nil context returned success" );
274
275         state = SIclose( si_ctx, cfd );
276         errors += fail_if_true( state == SI_ERROR, "close given good context and good fd returned error" );
277
278         state = SIclose( si_ctx, 5000 );                                                // out of range fd
279         errors += fail_if_true( state != SI_ERROR, "close given good context and bad fd returned success" );
280
281         state = SIclose( si_ctx, TCP_LISTEN_PORT );                             // close listener
282         errors += fail_if_true( state == SI_ERROR, "close given good context and listener fd returned error" );
283
284         state = SIclose( si_ctx, UDP_PORT );                                    // close first open udp port (should not be there)
285         errors += fail_if_true( state != SI_ERROR, "close given good context and udp generic fd returned error" );
286
287         buf = SIgetname( 3 );
288         if( fail_if_true( buf == NULL, "get name failed to return a buffer" ) ) {
289                 errors++;
290         } else {
291                 errors += fail_if_true( buf[0] == 0, "get name returned buf with emtpy string" );
292         }
293
294         fprintf( stderr, "<INFO> conn module finished with %d errors\n", errors );
295         return errors;
296 }
297
298 /*
299         Misc tests that just don't fit in another bucket.
300 */
301 static int misc( ) {
302         int errors = 0;
303         char    buf[1024];
304
305         SIcbreg( NULL, SI_CB_SECURITY, test_cb, NULL );         // coverage only, no return value no verification
306         SIcbreg( si_ctx, SI_CB_SECURITY, test_cb, NULL );
307
308         buf[0] = 0;
309         SIgetaddr( si_ctx, buf );
310         errors += fail_if_true( buf[0] == 0, "get address failed" );
311         fprintf( stderr, "<INFO> get address returns (%s)\n", buf );
312
313         fprintf( stderr, "<INFO> misc module finished with %d errors\n", errors );
314         return errors;
315 }
316
317
318 /*
319         New session (accept) testing.
320 */
321 static int new_sess( ) {
322         int errors = 0;
323         char    buf[1024];
324         struct tp_blk *tpptr;
325         int             status;
326
327         tpptr = SInew( TP_BLK );
328         tpptr->fd = 3;
329         tpptr->flags |= TPF_LISTENFD;
330
331         tpem_set_accept_fd( -1 );                                                                       // accept will "fail" for coverage
332         status = SInewsession( si_ctx, tpptr );
333         errors += fail_if_true( status != SI_ERROR, "newsession did not fail when accept fails" );
334
335         tpem_set_accept_fd( 5 );                                                                        // accept will return a good fd
336         SIcbreg( si_ctx, SI_CB_SECURITY, test_cb_err, NULL );           // register error and drive new session for error coverage
337         status = SInewsession( si_ctx, tpptr );
338         errors += fail_if_true( status >= 0, "newsession did failed when accept was good" );
339
340         tpem_set_accept_fd( 6 );                                                                        // accept will return a good fd
341         SIset_tflags( si_ctx, SI_TF_NODELAY | SI_TF_FASTACK );          // flip options for coverage in new sess
342         SIcbreg( si_ctx, SI_CB_CONN, test_cb, NULL );                           // drive connection for coverage
343         SIcbreg( si_ctx, SI_CB_SECURITY, test_cb, NULL );
344         status = SInewsession( si_ctx, tpptr );
345         errors += fail_if_true( status < 0, "newsession did failed when accept was good" );
346
347         fprintf( stderr, "<INFO> new_sess module finished with %d errors\n", errors );
348         return errors;
349 }
350
351 /*
352         Send tests
353 */
354 static int send_tests( ) {
355         int             errors = 0;
356         char    buf[1024];
357         int             len;
358         int             state;
359
360         len = snprintf( buf, 100, "Heaven knows I'm miserable now!" );
361
362         state = SIsendt( si_ctx, 9999, buf, len );
363         errors += fail_if_true( state >= 0, "send given fd out of range did not fail" );
364
365         state = SIsendt( si_ctx, -1, buf, len );
366         errors += fail_if_true( state >= 0, "send given neg fd did not fail" );
367
368         SIsendt( si_ctx, 6, buf, len );
369
370         tpem_set_send_err( 99 );
371         SIsendt( si_ctx, 6, buf, len );
372
373         tpem_set_send_err( 0 );
374         tpem_set_sel_blk( 1 );
375         SIsendt( si_ctx, 6, buf, len );
376
377         tpem_set_sel_blk( 0 );
378         tpem_set_selef_fd( 6 );                                         // will cause send to fail and fd6 to close
379         SIsendt( si_ctx, 6, buf, len );
380
381         return errors;
382 }
383
384
385 // ----------------------------------------------------------------------------------------
386
387 /*
388         Drive tests...
389 */
390 int main() {
391         int errors = 0;
392
393         rmr_set_vlevel( 5 );                    // enable all debugging
394
395         fprintf( stderr, "\n<INFO> starting SI95 tests\n" );
396
397         errors += init();
398         errors += memory();
399         errors += addr();
400         errors += conn();
401         errors += misc();
402
403         errors += new_sess();           // should leave a "connected" session at fd == 6
404         errors += send_tests();
405
406         errors += cleanup();
407
408         fprintf( stderr, "<INFO> si95 tests finished (%d)\n", errors );
409         if( errors == 0 ) {
410                 fprintf( stderr, "<PASS> all tests were OK\n\n" );
411         } else {
412                 fprintf( stderr, "<FAIL> %d errors in SI95 core code\n\n", errors );
413         }
414
415         return !!errors;
416 }