blob: 87f9931702060c035e8c777d5b0aa76ff6f3de98 [file] [log] [blame]
E. Scott Daniels8dd46412019-04-16 20:47:54 +00001// : vi ts=4 sw=4 noet :
2/*
3==================================================================================
E. Scott Daniels5efb1e62019-05-02 17:09:35 +00004 Copyright (c) 2019 Nokia
E. Scott Daniels8790bf02019-04-23 12:59:28 +00005 Copyright (c) 2018-2019 AT&T Intellectual Property.
E. Scott Daniels8dd46412019-04-16 20:47:54 +00006
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
E. Scott Daniels8790bf02019-04-23 12:59:28 +000011 http://www.apache.org/licenses/LICENSE-2.0
E. Scott Daniels8dd46412019-04-16 20:47:54 +000012
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
E. Scott Daniels5efb1e62019-05-02 17:09:35 +000024 time by the test driver.
E. Scott Daniels8dd46412019-04-16 20:47:54 +000025
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>
E. Scott Daniels412d53d2019-05-20 20:00:52 +000037#include <pthread.h>
38#include <semaphore.h>
E. Scott Daniels8dd46412019-04-16 20:47:54 +000039
E. Scott Daniels412d53d2019-05-20 20:00:52 +000040#include "rmr.h"
41#include "rmr_agnostic.h"
E. Scott Daniels8dd46412019-04-16 20:47:54 +000042
43typedef struct entry_info {
44 int group;
45 char* ep_name;
46} ei_t;
47
48
49/*
E. Scott Daniels3376a212019-05-14 14:14:20 +000050 Driven by symtab foreach element of one space.
51 We count using the data as a counter.
52*/
53static 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*/
66static 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/*
E. Scott Daniels6511ac72019-08-27 10:17:21 -040082 Builds a route table key.
83*/
84static uint64_t build_key( uint32_t mtype, uint32_t sid ) {
85 uint64_t k;
86
87 k = (uint64_t) sid << 32;
88 k += mtype;
89
90fprintf( stderr, "<INFO> build key: %x %x --> %llx\n", (int) mtype, (int) sid, (long long) k );
91 return k;
92}
93
94/*
E. Scott Daniels8dd46412019-04-16 20:47:54 +000095 This is the main route table test. It sets up a very specific table
96 for testing (not via the generic setup function for other test
97 situations).
98*/
99static int rt_test( ) {
100 uta_ctx_t* ctx; // context needed to test load static rt
101 route_table_t* rt; // route table
102 route_table_t* crt; // cloned route table
E. Scott Daniels6511ac72019-08-27 10:17:21 -0400103 rtable_ent_t* rte; // route table entries from table
104 rtable_ent_t* rte2;
E. Scott Daniels8dd46412019-04-16 20:47:54 +0000105 endpoint_t* ep; // endpoint added
106 int more = 0; // more flag from round robin
107 int errors = 0; // number errors found
108 int i;
109 int k;
E. Scott Daniels3376a212019-05-14 14:14:20 +0000110 int c1; // general counters
111 int c2;
E. Scott Daniels8dd46412019-04-16 20:47:54 +0000112 int mtype;
113 int value;
114 int alt_value;
115 ei_t entries[50]; // end point information
E. Scott Daniels6511ac72019-08-27 10:17:21 -0400116 int gcounts[7]; // number of groups in this set
117 int ecounts[7]; // number of elements per group
118 uint64_t mtypes[7]; // mtype/sid 'key' in the modern RMR world
E. Scott Daniels8dd46412019-04-16 20:47:54 +0000119 char* tok;
120 char* nxt_tok;
121 int enu = 0;
122 int state;
123 char *buf;
124 char* seed_fname; // seed file
125 nng_socket nn_sock; // this is a struct in nng, so difficult to validate
126
127 setenv( "ENV_VERBOSE_FILE", ".ut_rmr_verbose", 1 ); // allow for verbose code in rtc to be driven
E. Scott Danielsd7109572019-04-18 14:01:16 +0000128 i = open( ".ut_rmr_verbose", O_RDWR | O_CREAT, 0644 );
E. Scott Daniels8dd46412019-04-16 20:47:54 +0000129 if( i >= 0 ) {
E. Scott Daniels6511ac72019-08-27 10:17:21 -0400130 write( i, "2\n", 2 );
E. Scott Daniels8dd46412019-04-16 20:47:54 +0000131 close( i );
132 }
133
E. Scott Daniels6511ac72019-08-27 10:17:21 -0400134
135 /*
136 The hacky code below calls the necessary rmr functions to create a route table
137 as though the following were read and parsed by the rmr functions. (This tests
138 the individual funcitons and avoids writing another parser, so it's not pretty.)
139
140 mse | 0 | 0 | yahoo.com:4561,localhost:4562
141 mse | 1 | 0 | localhost:4560,localhost:4568,localhost:4569; localhost:4561,localhost:4562
142 mse | 2 | 0 | localhost:4563,localhost:4564
143 mse | 3 | 0 | localhost:4565
144 mse | 3 | 11 | locahost:5511
145 mse | 3 | -1 | localhost:5500
146 */
147 gcounts[0] = 1; // first entry has 1 group with 2 endpoints; message type 0, sid 0
E. Scott Daniels8dd46412019-04-16 20:47:54 +0000148 ecounts[0] = 2;
E. Scott Daniels6511ac72019-08-27 10:17:21 -0400149 mtypes[0] = build_key( 0, 0 ); // mtype is now a key of mtype/sid
E. Scott Daniels8dd46412019-04-16 20:47:54 +0000150 entries[enu].group = 0; entries[enu].ep_name = "yahoo.com:4561"; enu++; // use a dns resolvable name to test that
E. Scott Daniels6511ac72019-08-27 10:17:21 -0400151 entries[enu].group = 0; entries[enu].ep_name = "localhost:4562"; enu++; // rest can default to some dummy ip
E. Scott Daniels8dd46412019-04-16 20:47:54 +0000152
E. Scott Daniels6511ac72019-08-27 10:17:21 -0400153 gcounts[1] = 2; // 2 groups
154 ecounts[1] = 3; // first has 3 endpoints
155 mtypes[1] = build_key( 1, 0 );
156 entries[enu].group = 0; entries[enu].ep_name = "localhost:4560"; enu++;
E. Scott Daniels8dd46412019-04-16 20:47:54 +0000157 entries[enu].group = 0; entries[enu].ep_name = "localhost:4568"; enu++;
158 entries[enu].group = 0; entries[enu].ep_name = "localhost:4569"; enu++;
159
E. Scott Daniels6511ac72019-08-27 10:17:21 -0400160 gcounts[2] = 0; // 0 means use same rte, this is the next group for the entry
161 ecounts[2] = 2; // 2 endpoints
162 mtypes[2] = 999; // ignored when appending to previous entry
E. Scott Daniels8dd46412019-04-16 20:47:54 +0000163 entries[enu].group = 1; entries[enu].ep_name = "localhost:4561"; enu++;
164 entries[enu].group = 1; entries[enu].ep_name = "localhost:4562"; enu++;
165
E. Scott Daniels6511ac72019-08-27 10:17:21 -0400166 gcounts[3] = 1; // next entry has 1 group
167 ecounts[3] = 2; // with 2 enpoints
168 mtypes[3] = build_key( 2, 0 );
E. Scott Daniels8dd46412019-04-16 20:47:54 +0000169 entries[enu].group = 0; entries[enu].ep_name = "localhost:4563"; enu++;
170 entries[enu].group = 0; entries[enu].ep_name = "localhost:4564"; enu++;
171
E. Scott Daniels6511ac72019-08-27 10:17:21 -0400172 gcounts[4] = 1; // three entries for mt==3 with different sids
E. Scott Daniels8dd46412019-04-16 20:47:54 +0000173 ecounts[4] = 1;
E. Scott Daniels6511ac72019-08-27 10:17:21 -0400174 mtypes[4] = build_key( 3, 0 );
175 entries[enu].group = 0; entries[enu].ep_name = "localhost:5500"; enu++;
E. Scott Daniels8dd46412019-04-16 20:47:54 +0000176
E. Scott Daniels6511ac72019-08-27 10:17:21 -0400177 gcounts[5] = 1;
178 ecounts[5] = 1;
179 mtypes[5] = build_key( 3, 11 );
180 entries[enu].group = 0; entries[enu].ep_name = "localhost:5511"; enu++;
181
182 gcounts[6] = 1;
183 ecounts[6] = 1;
184 mtypes[6] = build_key( 3, -1 );
185 entries[enu].group = 0; entries[enu].ep_name = "localhost:5512"; enu++;
E. Scott Daniels8dd46412019-04-16 20:47:54 +0000186
187
188 rt = uta_rt_init( ); // get us a route table
189 if( (errors += fail_if_nil( rt, "pointer to route table" )) ) {
190 fprintf( stderr, "<FAIL> abort: cannot continue without a route table\n" );
191 exit( 1 );
192 }
193
194 enu = 0;
195 rte = NULL;
196 for( i = 0; i < sizeof( gcounts )/sizeof( int ); i++ ) { // add entries defined above
197 if( gcounts[i] ) {
198 rte = uta_add_rte( rt, mtypes[i], gcounts[i] ); // get/create entry for message type
199 if( (errors += fail_if_nil( rte, "route table entry" )) ) {
200 fprintf( stderr, "<FAIL> abort: cannot continue without a route table entry\n" );
201 exit( 1 );
202 }
203 } else {
204 if( rte == NULL ) {
205 fprintf( stderr, "<SNAFU> internal testing error -- rte was nil for gcount == 0\n" );
206 exit( 1 );
207 }
208 }
209
210 for( k = 0; k < ecounts[i]; k++ ) {
211 ep = uta_add_ep( rt, rte, entries[enu].ep_name, entries[enu].group );
212 errors += fail_if_nil( ep, "endpoint" );
213 enu++;
214 }
215 }
216
E. Scott Daniels6511ac72019-08-27 10:17:21 -0400217 // ----- end hacking together a route table ---------------------------------------------------
218
219
E. Scott Daniels3376a212019-05-14 14:14:20 +0000220 crt = uta_rt_clone( rt ); // clone only the endpoint entries
E. Scott Daniels8dd46412019-04-16 20:47:54 +0000221 errors += fail_if_nil( crt, "cloned route table" );
E. Scott Daniels3376a212019-05-14 14:14:20 +0000222 if( crt ) {
223 c1 = count_entries( rt, 1 );
224 c2 = count_entries( crt, 1 );
225 errors += fail_not_equal( c1, c2, "cloned (endpoints) table entries space 1 count (b) did not match original table count (a)" );
226
227 c2 = count_entries( crt, 0 );
228 errors += fail_not_equal( c2, 0, "cloned (endpoints) table entries space 0 count (a) was not zero as expected" );
229 uta_rt_drop( crt );
230 }
231
232
233 crt = uta_rt_clone_all( rt ); // clone all entries
234 errors += fail_if_nil( crt, "cloned all route table" );
235
236 if( crt ) {
237 c1 = count_entries( rt, 0 );
238 c2 = count_entries( crt, 0 );
239 errors += fail_not_equal( c1, c2, "cloned (all) table entries space 0 count (b) did not match original table count (a)" );
240
241 c1 = count_entries( rt, 1 );
242 c2 = count_entries( crt, 1 );
243 errors += fail_not_equal( c1, c2, "cloned (all) table entries space 1 count (b) did not match original table count (a)" );
244 uta_rt_drop( crt );
245 }
246
E. Scott Daniels8dd46412019-04-16 20:47:54 +0000247
248 ep = uta_get_ep( rt, "localhost:4561" );
249 errors += fail_if_nil( ep, "end point (fetch by name)" );
250 ep = uta_get_ep( rt, "bad_name:4560" );
251 errors += fail_not_nil( ep, "end point (fetch by name with bad name)" );
252
E. Scott Daniels58ccd682019-10-02 10:21:24 -0400253 ep = NULL;
254 state = uta_epsock_byname( rt, "localhost:4561", &nn_sock, &ep ); // this should be found
E. Scott Daniels8dd46412019-04-16 20:47:54 +0000255 errors += fail_if_equal( state, 0, "socket (by name)" );
E. Scott Daniels58ccd682019-10-02 10:21:24 -0400256 errors += fail_if_nil( ep, "epsock_byname did not populate endpoint pointer when expected to" );
E. Scott Daniels8dd46412019-04-16 20:47:54 +0000257 //alt_value = uta_epsock_byname( rt, "localhost:4562" ); // we might do a memcmp on the two structs, but for now nothing
258 //errors += fail_if_equal( value, alt_value, "app1/app2 sockets" );
259
E. Scott Daniels6511ac72019-08-27 10:17:21 -0400260
261 // --- test that the get_rte function finds expected keys, and retries to find 'bad' sid attempts for valid mtypes with no sid
262 rte = uta_get_rte( rt, 0, 1, TRUE ); // s=0 m=1 is defined, so this should return a pointer
263 errors += fail_if_nil( rte, "get_rte did not return a pointer when s=0 m=1 true given" );
264
265 rte = uta_get_rte( rt, 0, 1, FALSE ); // the retry shouldn't apply, but ensure it does the righ thing
266 errors += fail_if_nil( rte, "get_rte did not return a pointer when s=0 m=1 false given" );
267
268 rte = uta_get_rte( rt, 1000, 1, FALSE ); // s=1000 does not exist for any msg type; should return nil as not allowed to drop sid
269 errors += fail_not_nil( rte, "get_rte returned a pointer when s=1000 m=1 false given" );
270
271 rte = uta_get_rte( rt, 1000, 1, TRUE ); // this should also fail as there is no mt==1 sid==-1 defined
272 errors += fail_not_nil( rte, "get_rte returned a pointer when s=1000 m=1 true given" );
273
274 rte = uta_get_rte( rt, 0, 3, TRUE ); // mtype sid combo does exist; true/false should not matter
275 errors += fail_if_nil( rte, "get_rte did not return a pointer when s=0 m=3 true given" );
276
277 rte2 = uta_get_rte( rt, 11, 3, TRUE ); // same mtype as before, different (valid) group, rte should be different than before
278 errors += fail_if_nil( rte2, "get_rte did not return a pointer when s=11 m=3 true given" );
279 errors += fail_if_true( rte == rte2, "get_rte for mtype==3 and different sids (0 and 11) returned the same rte pointer" );
280
281 rte2 = uta_get_rte( rt, 0, 3, FALSE ); // since the mtype/sid combo exists, setting false should return the same as before
282 errors += fail_if_nil( rte2, "get_rte did not return a pointer when s=0 m=3 false given" );
283 errors += fail_if_false( rte == rte2, "get_rte did not return same pointer when mtype/sid combo given with different true/false" );
284
285 rte = uta_get_rte( rt, 12, 3, FALSE ); // this combo does not exist and should fail when alt-key is not allowed (false)
286 errors += fail_not_nil( rte, "get_rte returned a pointer for s=12, m=3, false" );
287
288 rte = uta_get_rte( rt, 12, 3, TRUE ); // this should return the entry for the 3/-1 combination
289 errors += fail_if_nil( rte, "get_rte did not return a pointer for s=12, m=3, true" );
290
E. Scott Daniels8dd46412019-04-16 20:47:54 +0000291 alt_value = -1;
E. Scott Daniels6511ac72019-08-27 10:17:21 -0400292 rte = uta_get_rte( rt, 0, 1, FALSE ); // get an rte for the next loop
293 if( rte ) {
294 for( i = 0; i < 10; i++ ) { // round robin return value should be different each time
E. Scott Daniels58ccd682019-10-02 10:21:24 -0400295 value = uta_epsock_rr( rte, 0, &more, &nn_sock, &ep ); // msg type 1, group 1
E. Scott Daniels6511ac72019-08-27 10:17:21 -0400296 errors += fail_if_equal( value, alt_value, "round robiin sockets with multiple end points" );
297 errors += fail_if_false( more, "more for mtype==1" );
298 alt_value = value;
299 }
E. Scott Daniels8dd46412019-04-16 20:47:54 +0000300 }
301
302 more = -1;
E. Scott Daniels6511ac72019-08-27 10:17:21 -0400303 rte = uta_get_rte( rt, 0, 3, FALSE ); // get an rte for the next loop
304 if( rte ) {
305 for( i = 0; i < 10; i++ ) { // this mtype has only one endpoint, so rr should be same each time
E. Scott Daniels58ccd682019-10-02 10:21:24 -0400306 value = uta_epsock_rr( rte, 0, NULL, &nn_sock, &ep ); // also test ability to deal properly with nil more pointer
E. Scott Daniels6511ac72019-08-27 10:17:21 -0400307 if( i ) {
308 errors += fail_not_equal( value, alt_value, "round robin sockets with one endpoint" );
309 errors += fail_not_equal( more, -1, "more value changed in single group instance" );
310 }
311 alt_value = value;
E. Scott Daniels8dd46412019-04-16 20:47:54 +0000312 }
E. Scott Daniels8dd46412019-04-16 20:47:54 +0000313 }
314
E. Scott Daniels6511ac72019-08-27 10:17:21 -0400315 rte = uta_get_rte( rt, 11, 3, TRUE );
E. Scott Daniels58ccd682019-10-02 10:21:24 -0400316 state = uta_epsock_rr( rte, 22, NULL, NULL, &ep );
E. Scott Daniels6511ac72019-08-27 10:17:21 -0400317 errors += fail_if_true( state, "uta_epsock_rr returned bad (non-zero) state when given nil socket pointer" );
E. Scott Daniels8dd46412019-04-16 20:47:54 +0000318
319 uta_rt_clone( NULL ); // verify null parms don't crash things
320 uta_rt_drop( NULL );
E. Scott Daniels58ccd682019-10-02 10:21:24 -0400321 uta_epsock_rr( NULL, 0, &more, &nn_sock, &ep ); // drive null case for coverage
E. Scott Daniels8dd46412019-04-16 20:47:54 +0000322 uta_add_rte( NULL, 99, 1 );
E. Scott Daniels6511ac72019-08-27 10:17:21 -0400323 uta_get_rte( NULL, 0, 1000, TRUE );
E. Scott Daniels8dd46412019-04-16 20:47:54 +0000324
325 fprintf( stderr, "[INFO] test: adding end points with nil data; warnings expected\n" );
326 uta_add_ep( NULL, NULL, "foo", 1 );
327 uta_add_ep( rt, NULL, "foo", 1 );
328
329 buf = uta_fib( ".gitignore" );
330 errors += fail_if_nil( buf, "buffer from read file into buffer" );
331 if( buf ) {
332 free( buf );
333 }
334 buf = uta_fib( "no-file" );
335 errors += fail_if_nil( buf, "buffer from read file into buffer (no file)" );
336 if( buf ) {
337 free( buf );
338 }
339
340 uta_rt_drop( rt );
E. Scott Daniels6511ac72019-08-27 10:17:21 -0400341 rt = NULL;
E. Scott Daniels8dd46412019-04-16 20:47:54 +0000342
E. Scott Daniels8dd46412019-04-16 20:47:54 +0000343 if( (ctx = (uta_ctx_t *) malloc( sizeof( uta_ctx_t ) )) != NULL ) {
344 memset( ctx, 0, sizeof( *ctx ) );
345
346 if( (seed_fname = getenv( "RMR_SEED_RT" )) != NULL ) {
E. Scott Daniels6511ac72019-08-27 10:17:21 -0400347 read_static_rt( ctx, 0 );
348 rt = ctx->rtable;
349 errors += fail_if_nil( rt, "read seed table didn't generate a rtable pointer in context" );
350 unsetenv( "RMR_SEED_RT" ); // remove for next test
E. Scott Daniels8dd46412019-04-16 20:47:54 +0000351 }
E. Scott Daniels6511ac72019-08-27 10:17:21 -0400352
353 read_static_rt( ctx, 0 ); // drive for not there coverage
E. Scott Daniels8dd46412019-04-16 20:47:54 +0000354 }
355
E. Scott Daniels6511ac72019-08-27 10:17:21 -0400356
357 buf = uta_fib( "no-suhch-file" ); // drive some error checking for coverage
358 if( buf ) {
359 free( buf );
360 }
E. Scott Daniels8dd46412019-04-16 20:47:54 +0000361
E. Scott Daniels8dd46412019-04-16 20:47:54 +0000362
E. Scott Daniels412d53d2019-05-20 20:00:52 +0000363 ep = (endpoint_t *) malloc( sizeof( *ep ) );
364 pthread_mutex_init( &ep->gate, NULL );
365 ep->name = strdup( "worm" );
366 ep->addr = NULL;
367 state = uta_link2( ep );
E. Scott Danielsa41c6f52019-04-23 18:24:25 +0000368 errors += fail_if_true( state, "link2 did not return false when given nil pointers" );
E. Scott Daniels5efb1e62019-05-02 17:09:35 +0000369
E. Scott Danielsa41c6f52019-04-23 18:24:25 +0000370
E. Scott Daniels8dd46412019-04-16 20:47:54 +0000371 return !!errors; // 1 or 0 regardless of count
372}