1 // : vi ts=4 sw=4 noet :
3 ==================================================================================
4 Copyright (c) 2019 Nokia
5 Copyright (c) 2018-2019 AT&T Intellectual Property.
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
11 http://www.apache.org/licenses/LICENSE-2.0
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 ==================================================================================
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.
26 Author: E. Scott Daniels
38 #include <semaphore.h>
41 #include "rmr_agnostic.h"
43 typedef struct entry_info {
50 Driven by symtab foreach element of one space.
51 We count using the data as a counter.
53 static void count_things( void* st, void* entry, char const* name, void* thing, void* vdata ) {
57 if( (counter = (int *) vdata) != NULL ) {
64 Returns the number of entries in the table for the given class.
66 static int count_entries( route_table_t* rt, int class ) {
76 rmr_sym_foreach_class( rt->hash, class, count_things, &counter ); // run each and update counter
82 Builds a route table key.
84 static uint64_t build_key( uint32_t mtype, uint32_t sid ) {
87 k = (uint64_t) sid << 32;
90 fprintf( stderr, "<INFO> build key: %x %x --> %llx\n", (int) mtype, (int) sid, (long long) k );
95 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
99 static 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
103 rtable_ent_t* rte; // route table entries from table
105 endpoint_t* ep; // endpoint added
106 int more = 0; // more flag from round robin
107 int errors = 0; // number errors found
110 int c1; // general counters
115 ei_t entries[50]; // end point information
116 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
124 char* seed_fname; // seed file
125 nng_socket nn_sock; // this is a struct in nng, so difficult to validate
126 rmr_mbuf_t* mbuf; // message for meid route testing
128 setenv( "ENV_VERBOSE_FILE", ".ut_rmr_verbose", 1 ); // allow for verbose code in rtc to be driven
129 i = open( ".ut_rmr_verbose", O_RDWR | O_CREAT, 0644 );
131 write( i, "2\n", 2 );
137 The hacky code below calls the necessary rmr functions to create a route table
138 as though the following were read and parsed by the rmr functions. (This tests
139 the individual funcitons and avoids writing another parser, so it's not pretty.)
141 mse | 0 | 0 | yahoo.com:4561,localhost:4562
142 mse | 1 | 0 | localhost:4560,localhost:4568,localhost:4569; localhost:4561,localhost:4562
143 mse | 2 | 0 | localhost:4563,localhost:4564
144 mse | 3 | 0 | localhost:4565
145 mse | 3 | 11 | locahost:5511
146 mse | 3 | -1 | localhost:5500
148 gcounts[0] = 1; // first entry has 1 group with 2 endpoints; message type 0, sid 0
150 mtypes[0] = build_key( 0, 0 ); // mtype is now a key of mtype/sid
151 entries[enu].group = 0; entries[enu].ep_name = "yahoo.com:4561"; enu++; // use a dns resolvable name to test that
152 entries[enu].group = 0; entries[enu].ep_name = "localhost:4562"; enu++; // rest can default to some dummy ip
154 gcounts[1] = 2; // 2 groups
155 ecounts[1] = 3; // first has 3 endpoints
156 mtypes[1] = build_key( 1, 0 );
157 entries[enu].group = 0; entries[enu].ep_name = "localhost:4560"; enu++;
158 entries[enu].group = 0; entries[enu].ep_name = "localhost:4568"; enu++;
159 entries[enu].group = 0; entries[enu].ep_name = "localhost:4569"; enu++;
161 gcounts[2] = 0; // 0 means use same rte, this is the next group for the entry
162 ecounts[2] = 2; // 2 endpoints
163 mtypes[2] = 999; // ignored when appending to previous entry
164 entries[enu].group = 1; entries[enu].ep_name = "localhost:4561"; enu++;
165 entries[enu].group = 1; entries[enu].ep_name = "localhost:4562"; enu++;
167 gcounts[3] = 1; // next entry has 1 group
168 ecounts[3] = 2; // with 2 enpoints
169 mtypes[3] = build_key( 2, 0 );
170 entries[enu].group = 0; entries[enu].ep_name = "localhost:4563"; enu++;
171 entries[enu].group = 0; entries[enu].ep_name = "localhost:4564"; enu++;
173 gcounts[4] = 1; // three entries for mt==3 with different sids
175 mtypes[4] = build_key( 3, 0 );
176 entries[enu].group = 0; entries[enu].ep_name = "localhost:5500"; enu++;
180 mtypes[5] = build_key( 3, 11 );
181 entries[enu].group = 0; entries[enu].ep_name = "localhost:5511"; enu++;
185 mtypes[6] = build_key( 3, -1 );
186 entries[enu].group = 0; entries[enu].ep_name = "localhost:5512"; enu++;
189 rt = uta_rt_init( ); // get us a route table
190 if( (errors += fail_if_nil( rt, "pointer to route table" )) ) {
191 fprintf( stderr, "<FAIL> abort: cannot continue without a route table\n" );
197 for( i = 0; i < sizeof( gcounts )/sizeof( int ); i++ ) { // add entries defined above
199 rte = uta_add_rte( rt, mtypes[i], gcounts[i] ); // get/create entry for message type
200 if( (errors += fail_if_nil( rte, "route table entry" )) ) {
201 fprintf( stderr, "<FAIL> abort: cannot continue without a route table entry\n" );
206 fprintf( stderr, "<SNAFU> internal testing error -- rte was nil for gcount == 0\n" );
211 for( k = 0; k < ecounts[i]; k++ ) {
212 ep = uta_add_ep( rt, rte, entries[enu].ep_name, entries[enu].group );
213 errors += fail_if_nil( ep, "endpoint" );
218 // ----- end hacking together a route table ---------------------------------------------------
221 crt = uta_rt_clone( rt ); // clone only the endpoint entries
222 errors += fail_if_nil( crt, "cloned route table" );
224 c1 = count_entries( rt, 1 );
225 c2 = count_entries( crt, 1 );
226 errors += fail_not_equal( c1, c2, "cloned (endpoints) table entries space 1 count (b) did not match original table count (a)" );
228 c2 = count_entries( crt, 0 );
229 errors += fail_not_equal( c2, 0, "cloned (endpoints) table entries space 0 count (a) was not zero as expected" );
234 crt = uta_rt_clone_all( rt ); // clone all entries
235 errors += fail_if_nil( crt, "cloned all route table" );
238 c1 = count_entries( rt, 0 );
239 c2 = count_entries( crt, 0 );
240 errors += fail_not_equal( c1, c2, "cloned (all) table entries space 0 count (b) did not match original table count (a)" );
242 c1 = count_entries( rt, 1 );
243 c2 = count_entries( crt, 1 );
244 errors += fail_not_equal( c1, c2, "cloned (all) table entries space 1 count (b) did not match original table count (a)" );
249 ep = uta_get_ep( rt, "localhost:4561" );
250 errors += fail_if_nil( ep, "end point (fetch by name)" );
251 ep = uta_get_ep( rt, "bad_name:4560" );
252 errors += fail_not_nil( ep, "end point (fetch by name with bad name)" );
255 state = uta_epsock_byname( rt, "localhost:4561", &nn_sock, &ep ); // this should be found
256 errors += fail_if_equal( state, 0, "socket (by name)" );
257 errors += fail_if_nil( ep, "epsock_byname did not populate endpoint pointer when expected to" );
258 //alt_value = uta_epsock_byname( rt, "localhost:4562" ); // we might do a memcmp on the two structs, but for now nothing
259 //errors += fail_if_equal( value, alt_value, "app1/app2 sockets" );
262 // --- test that the get_rte function finds expected keys, and retries to find 'bad' sid attempts for valid mtypes with no sid
263 rte = uta_get_rte( rt, 0, 1, TRUE ); // s=0 m=1 is defined, so this should return a pointer
264 errors += fail_if_nil( rte, "get_rte did not return a pointer when s=0 m=1 true given" );
266 rte = uta_get_rte( rt, 0, 1, FALSE ); // the retry shouldn't apply, but ensure it does the righ thing
267 errors += fail_if_nil( rte, "get_rte did not return a pointer when s=0 m=1 false given" );
269 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
270 errors += fail_not_nil( rte, "get_rte returned a pointer when s=1000 m=1 false given" );
272 rte = uta_get_rte( rt, 1000, 1, TRUE ); // this should also fail as there is no mt==1 sid==-1 defined
273 errors += fail_not_nil( rte, "get_rte returned a pointer when s=1000 m=1 true given" );
275 rte = uta_get_rte( rt, 0, 3, TRUE ); // mtype sid combo does exist; true/false should not matter
276 errors += fail_if_nil( rte, "get_rte did not return a pointer when s=0 m=3 true given" );
278 rte2 = uta_get_rte( rt, 11, 3, TRUE ); // same mtype as before, different (valid) group, rte should be different than before
279 errors += fail_if_nil( rte2, "get_rte did not return a pointer when s=11 m=3 true given" );
280 errors += fail_if_true( rte == rte2, "get_rte for mtype==3 and different sids (0 and 11) returned the same rte pointer" );
282 rte2 = uta_get_rte( rt, 0, 3, FALSE ); // since the mtype/sid combo exists, setting false should return the same as before
283 errors += fail_if_nil( rte2, "get_rte did not return a pointer when s=0 m=3 false given" );
284 errors += fail_if_false( rte == rte2, "get_rte did not return same pointer when mtype/sid combo given with different true/false" );
286 rte = uta_get_rte( rt, 12, 3, FALSE ); // this combo does not exist and should fail when alt-key is not allowed (false)
287 errors += fail_not_nil( rte, "get_rte returned a pointer for s=12, m=3, false" );
289 rte = uta_get_rte( rt, 12, 3, TRUE ); // this should return the entry for the 3/-1 combination
290 errors += fail_if_nil( rte, "get_rte did not return a pointer for s=12, m=3, true" );
293 rte = uta_get_rte( rt, 0, 1, FALSE ); // get an rte for the next loop
295 for( i = 0; i < 10; i++ ) { // round robin return value should be different each time
296 value = uta_epsock_rr( rte, 0, &more, &nn_sock, &ep ); // msg type 1, group 1
297 errors += fail_if_equal( value, alt_value, "round robiin sockets with multiple end points" );
298 errors += fail_if_false( more, "more for mtype==1" );
304 rte = uta_get_rte( rt, 0, 3, FALSE ); // get an rte for the next loop
306 for( i = 0; i < 10; i++ ) { // this mtype has only one endpoint, so rr should be same each time
307 value = uta_epsock_rr( rte, 0, NULL, &nn_sock, &ep ); // also test ability to deal properly with nil more pointer
309 errors += fail_not_equal( value, alt_value, "round robin sockets with one endpoint" );
310 errors += fail_not_equal( more, -1, "more value changed in single group instance" );
316 rte = uta_get_rte( rt, 11, 3, TRUE );
317 state = uta_epsock_rr( rte, 22, NULL, NULL, &ep );
318 errors += fail_if_true( state, "uta_epsock_rr returned bad (non-zero) state when given nil socket pointer" );
321 uta_rt_clone( NULL ); // verify null parms don't crash things
323 uta_epsock_rr( NULL, 0, &more, &nn_sock, &ep ); // drive null case for coverage
324 uta_add_rte( NULL, 99, 1 );
325 uta_get_rte( NULL, 0, 1000, TRUE );
327 fprintf( stderr, "[INFO] test: adding end points with nil data; warnings expected\n" );
328 uta_add_ep( NULL, NULL, "foo", 1 );
329 uta_add_ep( rt, NULL, "foo", 1 );
331 buf = uta_fib( ".gitignore" );
332 errors += fail_if_nil( buf, "buffer from read file into buffer" );
336 buf = uta_fib( "no-file" );
337 errors += fail_if_nil( buf, "buffer from read file into buffer (no file)" );
345 if( (ctx = (uta_ctx_t *) malloc( sizeof( uta_ctx_t ) )) != NULL ) {
346 memset( ctx, 0, sizeof( *ctx ) );
348 if( (seed_fname = getenv( "RMR_SEED_RT" )) != NULL ) {
349 read_static_rt( ctx, 0 );
351 errors += fail_if_nil( rt, "read seed table didn't generate a rtable pointer in context" );
352 unsetenv( "RMR_SEED_RT" ); // remove for next test
355 read_static_rt( ctx, 0 ); // drive for not there coverage
359 buf = uta_fib( "no-suhch-file" ); // drive some error checking for coverage
365 ep = (endpoint_t *) malloc( sizeof( *ep ) );
366 pthread_mutex_init( &ep->gate, NULL );
367 ep->name = strdup( "worm" );
369 state = uta_link2( ep );
370 errors += fail_if_true( state, "link2 did not return false when given nil pointers" );
372 // ----------------- test the meid support for looking up an endpoint based on the meid in the message -----
374 ctx->my_name = strdup( "my_host_name" ); // set up to load a rtable
375 ctx->my_ip = strdup( "192.168.1.30" );
376 gen_rt( ctx ); // generate a route table with meid entries and hang off ctx
378 mbuf = rmr_alloc_msg( ctx, 2048 ); // buffer to play with
380 rmr_str2meid( mbuf, "meid1" ); // id that we know is in the map
382 ep = NULL; // force to nil so we see it go non-nil
383 state = epsock_meid( ctx->rtable, mbuf, &nn_sock, &ep );
384 errors += fail_if_nil( ep, "ep was nil when looking up ep with known meid in message" );
385 errors += fail_not_equal( state, 1, "state was not true when looking up ep with known meid in message" );
387 rmr_str2meid( mbuf, "XXXmeid1" ); // id that we know is NOT in the map
388 state = epsock_meid( ctx->rtable, mbuf, &nn_sock, &ep );
389 // it is NOT a valid check to test ep for nil -- epsock_mied doesn't guarentee ep is set/cleared when state is false
390 errors += fail_not_equal( state, 0, "state was not false when looking up ep with unknown meid in message" );
392 return !!errors; // 1 or 0 regardless of count