enhance(API): Add multi-threaded call
[ric-plt/lib/rmr.git] / test / rt_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:       rt_static_test.c
23         Abstract:       Test the route table funcitons. These are meant to be included at compile
24                                 time by the test driver.
25
26         Author:         E. Scott Daniels
27         Date:           3 April 2019
28 */
29
30 #include <unistd.h>
31 #include <stdio.h>
32 #include <stdlib.h>
33 #include <strings.h>
34 #include <errno.h>
35 #include <string.h>
36 #include <stdint.h>
37 #include <pthread.h>
38 #include <semaphore.h>
39
40 #include "rmr.h"
41 #include "rmr_agnostic.h"
42
43 typedef struct entry_info {
44         int group;
45         char* ep_name;
46 } ei_t;
47
48
49 /*
50         Driven by symtab foreach element of one space.
51         We count using the data as a counter.
52 */
53 static void count_things( void* st, void* entry, char const* name, void* thing, void* vdata ) {
54         int* counter;
55
56         if( thing ) {
57                 if( (counter = (int *) vdata) != NULL ) {
58                         *counter++;
59                 }
60         }
61 }
62
63 /*
64         Returns the number of entries in the table for the given class.
65 */
66 static int count_entries( route_table_t* rt, int class ) {
67         int counter = 0;
68
69         if( ! rt ) {
70                 return 0;
71         }
72         if( !rt->hash ) {
73                 return 0;
74         }
75
76         rmr_sym_foreach_class( rt->hash, class, count_things, &counter );       // run each and update counter
77
78         return counter;
79 }
80
81 /*
82         This is the main route table test. It sets up a very specific table
83         for testing (not via the generic setup function for other test
84         situations).
85 */
86 static int rt_test( ) {
87         uta_ctx_t* ctx;                 // context needed to test load static rt
88         route_table_t* rt;              // route table
89         route_table_t* crt;             // cloned route table
90         rtable_ent_t*   rte;    // entry in the table
91         endpoint_t*     ep;                     // endpoint added
92         int more = 0;                   // more flag from round robin
93         int errors = 0;                 // number errors found
94         int     i;
95         int k;
96         int     c1;                                     // general counters
97         int c2;
98         int mtype;
99         int value;
100         int alt_value;
101         ei_t    entries[50];    // end point information
102         int             gcounts[5];             // number of groups in this set
103         int             ecounts[5];             // number of elements per group
104         int             mtypes[5];              // msg type for each group set
105         char*   tok;
106         char*   nxt_tok;
107         int             enu = 0;
108         int             state;
109         char    *buf;
110         char*   seed_fname;             // seed file
111         nng_socket nn_sock;             // this is a struct in nng, so difficult to validate
112
113         setenv( "ENV_VERBOSE_FILE", ".ut_rmr_verbose", 1 );                     // allow for verbose code in rtc to be driven
114         i = open( ".ut_rmr_verbose", O_RDWR | O_CREAT, 0644 );
115         if( i >= 0 ) {
116                 write( 1, "2\n", 2 );
117                 close( i );
118         }
119
120         gcounts[0] = 1;                 // build entry info -- this is hackish, but saves writing another parser
121         ecounts[0] = 2;
122         mtypes[0] = 0;
123         entries[enu].group = 0; entries[enu].ep_name = "yahoo.com:4561"; enu++;         // use a dns resolvable name to test that
124         entries[enu].group = 0; entries[enu].ep_name = "localhost:4562"; enu++; // rest can default to some dummy ip
125
126         gcounts[1] = 2;
127         ecounts[1] = 3;
128         mtypes[1] = 1;
129         entries[enu].group = 0; entries[enu].ep_name = "localhost:4561"; enu++;
130         entries[enu].group = 0; entries[enu].ep_name = "localhost:4568"; enu++;
131         entries[enu].group = 0; entries[enu].ep_name = "localhost:4569"; enu++;
132
133         gcounts[2] = 0;         // 0 groups means use same rte, this is the next gropup
134         ecounts[2] = 2;
135         mtypes[2] = 1;
136         entries[enu].group = 1; entries[enu].ep_name = "localhost:4561"; enu++;
137         entries[enu].group = 1; entries[enu].ep_name = "localhost:4562"; enu++;
138
139         gcounts[3] = 1;         // 0 groups means use same rte, this is the next gropup
140         ecounts[3] = 2;
141         mtypes[3] = 2;
142         entries[enu].group = 0; entries[enu].ep_name = "localhost:4563"; enu++;
143         entries[enu].group = 0; entries[enu].ep_name = "localhost:4564"; enu++;
144
145         gcounts[4] = 1;         // 0 groups means use same rte, this is the next gropup
146         ecounts[4] = 1;
147         mtypes[4] = 3;
148         entries[enu].group = 0; entries[enu].ep_name = "localhost:4565"; enu++;
149
150
151
152         rt = uta_rt_init( );                                                                            // get us a route table
153         if( (errors += fail_if_nil( rt, "pointer to route table" )) ) {
154                 fprintf( stderr, "<FAIL> abort: cannot continue without a route table\n" );
155                 exit( 1 );
156         }
157
158         enu = 0;
159         rte = NULL;
160         for( i = 0; i < sizeof( gcounts )/sizeof( int ); i++ ) {                                // add entries defined above
161                 if( gcounts[i] ) {
162                         rte = uta_add_rte( rt, mtypes[i], gcounts[i] );                                 // get/create entry for message type
163                         if( (errors += fail_if_nil( rte, "route table entry" )) ) {
164                                 fprintf( stderr, "<FAIL> abort: cannot continue without a route table entry\n" );
165                                 exit( 1 );
166                         }
167                 } else {
168                         if( rte == NULL ) {
169                                 fprintf( stderr, "<SNAFU> internal testing error -- rte was nil for gcount == 0\n" );
170                                 exit( 1 );
171                         }
172                 }
173
174                 for( k = 0; k < ecounts[i]; k++ ) {
175                         ep = uta_add_ep( rt, rte, entries[enu].ep_name, entries[enu].group );
176                         errors += fail_if_nil( ep, "endpoint" );
177                         enu++;
178                 }
179         }
180
181         crt = uta_rt_clone( rt );                                                               // clone only the endpoint entries
182         errors += fail_if_nil( crt, "cloned route table" );
183         if( crt ) {
184                 c1 = count_entries( rt, 1 );
185                 c2 = count_entries( crt, 1 );
186                 errors += fail_not_equal( c1, c2, "cloned (endpoints) table entries space 1 count (b) did not match original table count (a)" );
187         
188                 c2 = count_entries( crt, 0 );
189                 errors += fail_not_equal( c2, 0, "cloned (endpoints) table entries space 0 count (a) was not zero as expected" );
190                 uta_rt_drop( crt );
191         }
192
193
194         crt = uta_rt_clone_all( rt );                                                   // clone all entries
195         errors += fail_if_nil( crt, "cloned all route table" );
196
197         if( crt ) {
198                 c1 = count_entries( rt, 0 );
199                 c2 = count_entries( crt, 0 );
200                 errors += fail_not_equal( c1, c2, "cloned (all) table entries space 0 count (b) did not match original table count (a)" );
201         
202                 c1 = count_entries( rt, 1 );
203                 c2 = count_entries( crt, 1 );
204                 errors += fail_not_equal( c1, c2, "cloned (all) table entries space 1 count (b) did not match original table count (a)" );
205                 uta_rt_drop( crt );
206         }
207         
208
209         ep = uta_get_ep( rt, "localhost:4561" );
210         errors += fail_if_nil( ep, "end point (fetch by name)" );
211         ep = uta_get_ep( rt, "bad_name:4560" );
212         errors += fail_not_nil( ep, "end point (fetch by name with bad name)" );
213
214         state = uta_epsock_byname( rt, "localhost:4561", &nn_sock );            // this should be found
215         errors += fail_if_equal( state, 0, "socket (by name)" );
216         //alt_value = uta_epsock_byname( rt, "localhost:4562" );                        // we might do a memcmp on the two structs, but for now nothing
217         //errors += fail_if_equal( value, alt_value, "app1/app2 sockets" );
218
219         alt_value = -1;
220         for( i = 0; i < 10; i++ ) {                                                                             // round robin return value should be different each time
221                 value = uta_epsock_rr( rt, 1, 0, &more, &nn_sock );                     // msg type 1, group 1
222                 errors += fail_if_equal( value, alt_value, "round robiin sockets with multiple end points" );
223                 errors += fail_if_false( more, "more for mtype==1" );
224                 alt_value = value;
225         }
226
227         more = -1;
228         for( i = 0; i < 10; i++ ) {                                                     // this mtype has only one endpoint, so rr should be same each time
229                 value = uta_epsock_rr( rt, 3, 0, NULL, &nn_sock );              // also test ability to deal properly with nil more pointer
230                 if( i ) {
231                         errors += fail_not_equal( value, alt_value, "round robin sockets with one endpoint" );
232                         errors += fail_not_equal( more, -1, "more value changed in single group instance" );
233                 }
234                 alt_value = value;
235         }
236
237         value = uta_epsock_rr( rt, 9, 0, &more, &nn_sock );                     // non-existant message type; should return false (0)
238         errors += fail_not_equal( value, 0, "socket for bad mtype was valid" );
239
240         uta_rt_clone( NULL );                                                           // verify null parms don't crash things
241         uta_rt_drop( NULL );
242         uta_epsock_rr( NULL, 1, 0, &more, &nn_sock );           // drive null case for coverage
243         uta_add_rte( NULL, 99, 1 );
244
245         fprintf( stderr, "[INFO] test: adding end points with nil data; warnings expected\n" );
246         uta_add_ep( NULL, NULL, "foo", 1 );
247         uta_add_ep( rt, NULL, "foo", 1 );
248
249         buf = uta_fib( ".gitignore" );
250         errors += fail_if_nil( buf, "buffer from read file into buffer" );
251         if( buf ) {
252                 free( buf );
253         }
254         buf = uta_fib( "no-file" );
255         errors += fail_if_nil( buf, "buffer from read file into buffer (no file)" );
256         if( buf ) {
257                 free( buf );
258         }
259
260         uta_rt_drop( rt );
261
262         if( (ctx = (uta_ctx_t *) malloc( sizeof( uta_ctx_t ) )) != NULL ) {
263                 memset( ctx, 0, sizeof( *ctx ) );
264
265                 if( (seed_fname = getenv( "RMR_SEED_RT" )) != NULL ) {
266                         if( ! (fail_if_nil( rt, "pointer to rt for load test" )) ) {
267                                 errors++;
268                                 read_static_rt( ctx, 0 );
269                                 unsetenv( "RMR_SEED_RT" );                      // unset to test the does not exist condition
270                                 read_static_rt( ctx, 0 );
271                         } else {
272                                 fprintf( stderr, "<FAIL> cannot gen rt for load test\n" );
273                         }
274                 } else {
275                         read_static_rt( ctx, 0 );               // not defined, just drive for that one case
276                 }
277         }
278
279         uta_fib( "no-suhch-file" );                     // drive some error checking for coverage
280
281
282         ep = (endpoint_t *) malloc( sizeof( *ep ) );
283         pthread_mutex_init( &ep->gate, NULL );
284         ep->name = strdup( "worm" );
285         ep->addr = NULL;
286         state = uta_link2( ep );
287         errors += fail_if_true( state, "link2 did not return false when given nil pointers" );
288
289         state = uta_epsock_rr( rt, 122, 0, NULL, NULL );
290         errors += fail_if_true( state, "uta_epsock_rr returned bad state when given nil socket pointer" );
291
292         rt = uta_rt_init( );                                                                            // get us a route table
293         state = uta_epsock_rr( rt, 0, -1, NULL, &nn_sock );
294         errors += fail_if_true( state, "uta_epsock_rr returned bad state (true) when given negative group number" );
295
296         return !!errors;                        // 1 or 0 regardless of count
297 }