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