Fix meid related core dump
[ric-plt/lib/rmr.git] / test / rt_static_test.c
index 26f81b7..9559004 100644 (file)
@@ -1,14 +1,14 @@
 // : vi ts=4 sw=4 noet :
 /*
 ==================================================================================
 // : vi ts=4 sw=4 noet :
 /*
 ==================================================================================
-        Copyright (c) 2019 Nokia 
-        Copyright (c) 2018-2019 AT&T Intellectual Property.
+           Copyright (c) 2019 Nokia
+           Copyright (c) 2018-2019 AT&T Intellectual Property.
 
    Licensed under the Apache License, Version 2.0 (the "License");
    you may not use this file except in compliance with the License.
    You may obtain a copy of the License at
 
 
    Licensed under the Apache License, Version 2.0 (the "License");
    you may not use this file except in compliance with the License.
    You may obtain a copy of the License at
 
-       http://www.apache.org/licenses/LICENSE-2.0
+          http://www.apache.org/licenses/LICENSE-2.0
 
    Unless required by applicable law or agreed to in writing, software
    distributed under the License is distributed on an "AS IS" BASIS,
 
    Unless required by applicable law or agreed to in writing, software
    distributed under the License is distributed on an "AS IS" BASIS,
@@ -21,7 +21,7 @@
 /*
        Mmemonic:       rt_static_test.c
        Abstract:       Test the route table funcitons. These are meant to be included at compile
 /*
        Mmemonic:       rt_static_test.c
        Abstract:       Test the route table funcitons. These are meant to be included at compile
-                               time by the test driver.  
+                               time by the test driver.
 
        Author:         E. Scott Daniels
        Date:           3 April 2019
 
        Author:         E. Scott Daniels
        Date:           3 April 2019
 #include <errno.h>
 #include <string.h>
 #include <stdint.h>
 #include <errno.h>
 #include <string.h>
 #include <stdint.h>
+#include <pthread.h>
+#include <semaphore.h>
 
 
-#include "../src/common/include/rmr.h"
-#include "../src/common/include/rmr_agnostic.h"
+#include "rmr.h"
+#include "rmr_agnostic.h"
 
 typedef struct entry_info {
        int group;
 
 typedef struct entry_info {
        int group;
@@ -44,6 +46,51 @@ typedef struct entry_info {
 } ei_t;
 
 
 } ei_t;
 
 
+/*
+       Driven by symtab foreach element of one space.
+       We count using the data as a counter.
+*/
+static void count_things( void* st, void* entry, char const* name, void* thing, void* vdata ) {
+       int* counter;
+
+       if( thing ) {
+               if( (counter = (int *) vdata) != NULL ) {
+                       *counter++;
+               }
+       }
+}
+
+/*
+       Returns the number of entries in the table for the given class.
+*/
+static int count_entries( route_table_t* rt, int class ) {
+       int counter = 0;
+
+       if( ! rt ) {
+               return 0;
+       }
+       if( !rt->hash ) {
+               return 0;
+       }
+
+       rmr_sym_foreach_class( rt->hash, class, count_things, &counter );       // run each and update counter
+
+       return counter;
+}
+
+/*
+       Builds a route table key.
+*/
+static uint64_t build_key( uint32_t mtype, uint32_t sid ) {
+       uint64_t k;
+
+       k = (uint64_t) sid << 32;
+       k += mtype;
+
+fprintf( stderr, "<INFO> build key: %x %x --> %llx\n", (int) mtype, (int) sid, (long long) k );
+       return k;
+}
+
 /*
        This is the main route table test. It sets up a very specific table
        for testing (not via the generic setup function for other test
 /*
        This is the main route table test. It sets up a very specific table
        for testing (not via the generic setup function for other test
@@ -53,19 +100,22 @@ static int rt_test( ) {
        uta_ctx_t* ctx;                 // context needed to test load static rt
        route_table_t* rt;              // route table
        route_table_t* crt;             // cloned route table
        uta_ctx_t* ctx;                 // context needed to test load static rt
        route_table_t* rt;              // route table
        route_table_t* crt;             // cloned route table
-       rtable_ent_t*   rte;    // entry in the table
+       rtable_ent_t*   rte;    // route table entries from table
+       rtable_ent_t*   rte2;
        endpoint_t*     ep;                     // endpoint added
        int more = 0;                   // more flag from round robin
        int errors = 0;                 // number errors found
        int     i;
        int k;
        endpoint_t*     ep;                     // endpoint added
        int more = 0;                   // more flag from round robin
        int errors = 0;                 // number errors found
        int     i;
        int k;
+       int     c1;                                     // general counters
+       int c2;
        int mtype;
        int value;
        int alt_value;
        ei_t    entries[50];    // end point information
        int mtype;
        int value;
        int alt_value;
        ei_t    entries[50];    // end point information
-       int             gcounts[5];             // number of groups in this set
-       int             ecounts[5];             // number of elements per group
-       int             mtypes[5];              // msg type for each group set
+       int             gcounts[7];             // number of groups in this set
+       int             ecounts[7];             // number of elements per group
+       uint64_t        mtypes[7];      // mtype/sid 'key' in the modern RMR world
        char*   tok;
        char*   nxt_tok;
        int             enu = 0;
        char*   tok;
        char*   nxt_tok;
        int             enu = 0;
@@ -73,44 +123,67 @@ static int rt_test( ) {
        char    *buf;
        char*   seed_fname;             // seed file
        nng_socket nn_sock;             // this is a struct in nng, so difficult to validate
        char    *buf;
        char*   seed_fname;             // seed file
        nng_socket nn_sock;             // this is a struct in nng, so difficult to validate
+       rmr_mbuf_t*     mbuf;           // message for meid route testing
 
        setenv( "ENV_VERBOSE_FILE", ".ut_rmr_verbose", 1 );                     // allow for verbose code in rtc to be driven
        i = open( ".ut_rmr_verbose", O_RDWR | O_CREAT, 0644 );
        if( i >= 0 ) {
 
        setenv( "ENV_VERBOSE_FILE", ".ut_rmr_verbose", 1 );                     // allow for verbose code in rtc to be driven
        i = open( ".ut_rmr_verbose", O_RDWR | O_CREAT, 0644 );
        if( i >= 0 ) {
-               write( 1, "2\n", 2 );
+               write( i, "2\n", 2 );
                close( i );
        }
 
                close( i );
        }
 
-       gcounts[0] = 1;                 // build entry info -- this is hackish, but saves writing another parser
+                                                       
+       /*
+               The hacky code below calls the necessary rmr functions to create a route table
+               as though the following were read and parsed by the rmr functions. (This tests
+               the individual funcitons and avoids writing another parser, so it's not pretty.)
+       
+               mse | 0 | 0 | yahoo.com:4561,localhost:4562
+               mse | 1 | 0 | localhost:4560,localhost:4568,localhost:4569; localhost:4561,localhost:4562
+               mse | 2 | 0 | localhost:4563,localhost:4564
+               mse | 3 | 0 | localhost:4565
+               mse | 3 | 11 | locahost:5511
+               mse | 3 | -1 | localhost:5500
+       */
+       gcounts[0] = 1;                                                 // first entry has 1 group with 2 endpoints; message type 0, sid 0
        ecounts[0] = 2;
        ecounts[0] = 2;
-       mtypes[0] = 0;
+       mtypes[0] = build_key( 0, 0 );                  // mtype is now a key of mtype/sid
        entries[enu].group = 0; entries[enu].ep_name = "yahoo.com:4561"; enu++;         // use a dns resolvable name to test that
        entries[enu].group = 0; entries[enu].ep_name = "yahoo.com:4561"; enu++;         // use a dns resolvable name to test that
-       entries[enu].group = 0; entries[enu].ep_name = "localhost:4562"; enu++; // rest can default to some dummy ip
+       entries[enu].group = 0; entries[enu].ep_name = "localhost:4562"; enu++;         // rest can default to some dummy ip
 
 
-       gcounts[1] = 2;
-       ecounts[1] = 3;
-       mtypes[1] = 1;
-       entries[enu].group = 0; entries[enu].ep_name = "localhost:4561"; enu++;
+       gcounts[1] = 2;                         // 2 groups
+       ecounts[1] = 3;                         // first has 3 endpoints
+       mtypes[1] = build_key( 1, 0 );
+       entries[enu].group = 0; entries[enu].ep_name = "localhost:4560"; enu++;
        entries[enu].group = 0; entries[enu].ep_name = "localhost:4568"; enu++;
        entries[enu].group = 0; entries[enu].ep_name = "localhost:4569"; enu++;
 
        entries[enu].group = 0; entries[enu].ep_name = "localhost:4568"; enu++;
        entries[enu].group = 0; entries[enu].ep_name = "localhost:4569"; enu++;
 
-       gcounts[2] = 0;         // 0 groups means use same rte, this is the next gropup
-       ecounts[2] = 2;
-       mtypes[2] = 1;
+       gcounts[2] = 0;                                 // 0 means use same rte, this is the next group for the entry
+       ecounts[2] = 2;                                 // 2 endpoints
+       mtypes[2] = 999;                                // ignored when appending to previous entry
        entries[enu].group = 1; entries[enu].ep_name = "localhost:4561"; enu++;
        entries[enu].group = 1; entries[enu].ep_name = "localhost:4562"; enu++;
 
        entries[enu].group = 1; entries[enu].ep_name = "localhost:4561"; enu++;
        entries[enu].group = 1; entries[enu].ep_name = "localhost:4562"; enu++;
 
-       gcounts[3] = 1;         // 0 groups means use same rte, this is the next gropup
-       ecounts[3] = 2;
-       mtypes[3] = 2;
+       gcounts[3] = 1;                                 // next entry has 1 group
+       ecounts[3] = 2;                                 // with 2 enpoints
+       mtypes[3] = build_key( 2, 0 );
        entries[enu].group = 0; entries[enu].ep_name = "localhost:4563"; enu++;
        entries[enu].group = 0; entries[enu].ep_name = "localhost:4564"; enu++;
 
        entries[enu].group = 0; entries[enu].ep_name = "localhost:4563"; enu++;
        entries[enu].group = 0; entries[enu].ep_name = "localhost:4564"; enu++;
 
-       gcounts[4] = 1;         // 0 groups means use same rte, this is the next gropup
+       gcounts[4] = 1;                                 // three entries for mt==3 with different sids
        ecounts[4] = 1;
        ecounts[4] = 1;
-       mtypes[4] = 3;
-       entries[enu].group = 0; entries[enu].ep_name = "localhost:4565"; enu++;
+       mtypes[4] = build_key( 3, 0 );
+       entries[enu].group = 0; entries[enu].ep_name = "localhost:5500"; enu++;
+
+       gcounts[5] = 1;
+       ecounts[5] = 1;
+       mtypes[5] = build_key( 3, 11 );
+       entries[enu].group = 0; entries[enu].ep_name = "localhost:5511"; enu++;
 
 
+       gcounts[6] = 1;
+       ecounts[6] = 1;
+       mtypes[6] = build_key( 3, -1 );
+       entries[enu].group = 0; entries[enu].ep_name = "localhost:5512"; enu++;
 
 
        rt = uta_rt_init( );                                                                            // get us a route table
 
 
        rt = uta_rt_init( );                                                                            // get us a route table
@@ -142,44 +215,114 @@ static int rt_test( ) {
                }
        }
 
                }
        }
 
-       crt = uta_rt_clone( rt );
+       // ----- end hacking together a route table ---------------------------------------------------
+
+
+       crt = uta_rt_clone( rt );                                                               // clone only the endpoint entries
        errors += fail_if_nil( crt, "cloned route table" );
        errors += fail_if_nil( crt, "cloned route table" );
+       if( crt ) {
+               c1 = count_entries( rt, 1 );
+               c2 = count_entries( crt, 1 );
+               errors += fail_not_equal( c1, c2, "cloned (endpoints) table entries space 1 count (b) did not match original table count (a)" );
+       
+               c2 = count_entries( crt, 0 );
+               errors += fail_not_equal( c2, 0, "cloned (endpoints) table entries space 0 count (a) was not zero as expected" );
+               uta_rt_drop( crt );
+       }
+
+
+       crt = uta_rt_clone_all( rt );                                                   // clone all entries
+       errors += fail_if_nil( crt, "cloned all route table" );
+
+       if( crt ) {
+               c1 = count_entries( rt, 0 );
+               c2 = count_entries( crt, 0 );
+               errors += fail_not_equal( c1, c2, "cloned (all) table entries space 0 count (b) did not match original table count (a)" );
+       
+               c1 = count_entries( rt, 1 );
+               c2 = count_entries( crt, 1 );
+               errors += fail_not_equal( c1, c2, "cloned (all) table entries space 1 count (b) did not match original table count (a)" );
+               uta_rt_drop( crt );
+       }
+       
 
        ep = uta_get_ep( rt, "localhost:4561" );
        errors += fail_if_nil( ep, "end point (fetch by name)" );
        ep = uta_get_ep( rt, "bad_name:4560" );
        errors += fail_not_nil( ep, "end point (fetch by name with bad name)" );
 
 
        ep = uta_get_ep( rt, "localhost:4561" );
        errors += fail_if_nil( ep, "end point (fetch by name)" );
        ep = uta_get_ep( rt, "bad_name:4560" );
        errors += fail_not_nil( ep, "end point (fetch by name with bad name)" );
 
-       state = uta_epsock_byname( rt, "localhost:4561", &nn_sock );            // this should be found
+       ep = NULL;
+       state = uta_epsock_byname( rt, "localhost:4561", &nn_sock, &ep );               // this should be found
        errors += fail_if_equal( state, 0, "socket (by name)" );
        errors += fail_if_equal( state, 0, "socket (by name)" );
+       errors += fail_if_nil( ep, "epsock_byname did not populate endpoint pointer when expected to" );
        //alt_value = uta_epsock_byname( rt, "localhost:4562" );                        // we might do a memcmp on the two structs, but for now nothing
        //errors += fail_if_equal( value, alt_value, "app1/app2 sockets" );
 
        //alt_value = uta_epsock_byname( rt, "localhost:4562" );                        // we might do a memcmp on the two structs, but for now nothing
        //errors += fail_if_equal( value, alt_value, "app1/app2 sockets" );
 
+
+       // --- test that the get_rte function finds expected keys, and retries to find 'bad' sid attempts for valid mtypes with no sid
+       rte = uta_get_rte( rt, 0, 1, TRUE );                    // s=0 m=1 is defined, so this should return a pointer
+       errors += fail_if_nil( rte, "get_rte did not return a pointer when s=0 m=1 true given" );
+
+       rte = uta_get_rte( rt, 0, 1, FALSE );                   // the retry shouldn't apply, but ensure it does the righ thing
+       errors += fail_if_nil( rte, "get_rte did not return a pointer when s=0 m=1 false given" );
+
+       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
+       errors += fail_not_nil( rte, "get_rte returned a pointer when s=1000 m=1 false given" );
+
+       rte = uta_get_rte( rt, 1000, 1, TRUE );                 // this should also fail as there is no mt==1 sid==-1 defined
+       errors += fail_not_nil( rte, "get_rte returned a pointer when s=1000 m=1 true given" );
+
+       rte = uta_get_rte( rt, 0, 3, TRUE );                    // mtype sid combo does exist; true/false should not matter
+       errors += fail_if_nil( rte, "get_rte did not return a pointer when s=0 m=3 true given" );
+
+       rte2 = uta_get_rte( rt, 11, 3, TRUE );                  // same mtype as before, different (valid) group, rte should be different than before
+       errors += fail_if_nil( rte2, "get_rte did not return a pointer when s=11 m=3 true given" );
+       errors += fail_if_true( rte == rte2, "get_rte for mtype==3 and different sids (0 and 11) returned the same rte pointer" );
+
+       rte2 = uta_get_rte( rt, 0, 3, FALSE );                  // since the mtype/sid combo exists, setting false should return the same as before
+       errors += fail_if_nil( rte2, "get_rte did not return a pointer when s=0 m=3 false given" );
+       errors += fail_if_false( rte == rte2, "get_rte did not return same pointer when mtype/sid combo given with different true/false" );
+
+       rte = uta_get_rte( rt, 12, 3, FALSE );                  // this combo does not exist and should fail when alt-key is not allowed (false)
+       errors += fail_not_nil( rte, "get_rte returned a pointer for s=12, m=3, false" );
+
+       rte = uta_get_rte( rt, 12, 3, TRUE );                   // this should return the entry for the 3/-1 combination 
+       errors += fail_if_nil( rte, "get_rte did not return a pointer for s=12, m=3, true" );
+
        alt_value = -1;
        alt_value = -1;
-       for( i = 0; i < 10; i++ ) {                                                                             // round robin return value should be different each time
-               value = uta_epsock_rr( rt, 1, 0, &more, &nn_sock );                     // msg type 1, group 1
-               errors += fail_if_equal( value, alt_value, "round robiin sockets with multiple end points" );
-               errors += fail_if_false( more, "more for mtype==1" );
-               alt_value = value;
+       rte = uta_get_rte( rt, 0, 1, FALSE );                   // get an rte for the next loop
+       if( rte ) {
+               for( i = 0; i < 10; i++ ) {                                                                     // round robin return value should be different each time
+                       value = uta_epsock_rr( rte, 0, &more, &nn_sock, &ep );          // msg type 1, group 1
+                       errors += fail_if_equal( value, alt_value, "round robiin sockets with multiple end points" );
+                       errors += fail_if_false( more, "more for mtype==1" );
+                       alt_value = value;
+               }
        }
 
        more = -1;
        }
 
        more = -1;
-       for( i = 0; i < 10; i++ ) {                                                     // this mtype has only one endpoint, so rr should be same each time
-               value = uta_epsock_rr( rt, 3, 0, NULL, &nn_sock );              // also test ability to deal properly with nil more pointer
-               if( i ) {
-                       errors += fail_not_equal( value, alt_value, "round robin sockets with one endpoint" );
-                       errors += fail_not_equal( more, -1, "more value changed in single group instance" );
+       rte = uta_get_rte( rt, 0, 3, FALSE );                           // get an rte for the next loop
+       if( rte ) {
+               for( i = 0; i < 10; i++ ) {                                                             // this mtype has only one endpoint, so rr should be same each time
+                       value = uta_epsock_rr( rte, 0, NULL, &nn_sock, &ep );           // also test ability to deal properly with nil more pointer
+                       if( i ) {
+                               errors += fail_not_equal( value, alt_value, "round robin sockets with one endpoint" );
+                               errors += fail_not_equal( more, -1, "more value changed in single group instance" );
+                       }
+                       alt_value = value;
                }
                }
-               alt_value = value;
        }
 
        }
 
-       value = uta_epsock_rr( rt, 9, 0, &more, &nn_sock );                     // non-existant message type; should return false (0)
-       errors += fail_not_equal( value, 0, "socket for bad mtype was valid" );
+       rte = uta_get_rte( rt, 11, 3, TRUE );
+       state = uta_epsock_rr( rte, 22, NULL, NULL, &ep );
+       errors += fail_if_true( state, "uta_epsock_rr returned bad (non-zero) state when given nil socket pointer" );
+
 
        uta_rt_clone( NULL );                                                           // verify null parms don't crash things
        uta_rt_drop( NULL );
 
        uta_rt_clone( NULL );                                                           // verify null parms don't crash things
        uta_rt_drop( NULL );
-       uta_epsock_rr( NULL, 1, 0, &more, &nn_sock );           // drive null case for coverage
+       uta_epsock_rr( NULL, 0,  &more, &nn_sock, &ep );                        // drive null case for coverage
        uta_add_rte( NULL, 99, 1 );
        uta_add_rte( NULL, 99, 1 );
+       uta_get_rte( NULL, 0, 1000, TRUE );
 
        fprintf( stderr, "[INFO] test: adding end points with nil data; warnings expected\n" );
        uta_add_ep( NULL, NULL, "foo", 1 );
 
        fprintf( stderr, "[INFO] test: adding end points with nil data; warnings expected\n" );
        uta_add_ep( NULL, NULL, "foo", 1 );
@@ -197,36 +340,54 @@ static int rt_test( ) {
        }
 
        uta_rt_drop( rt );
        }
 
        uta_rt_drop( rt );
-
-       uta_rt_drop( crt );
+       rt = NULL;
 
        if( (ctx = (uta_ctx_t *) malloc( sizeof( uta_ctx_t ) )) != NULL ) {
                memset( ctx, 0, sizeof( *ctx ) );
 
                if( (seed_fname = getenv( "RMR_SEED_RT" )) != NULL ) {
 
        if( (ctx = (uta_ctx_t *) malloc( sizeof( uta_ctx_t ) )) != NULL ) {
                memset( ctx, 0, sizeof( *ctx ) );
 
                if( (seed_fname = getenv( "RMR_SEED_RT" )) != NULL ) {
-                       if( ! (fail_if_nil( rt, "pointer to rt for load test" )) ) {
-                               errors++;
-                               read_static_rt( ctx, 0 );
-                               unsetenv( "RMR_SEED_RT" );                      // unset to test the does not exist condition
-                               read_static_rt( ctx, 0 );
-                       } else {
-                               fprintf( stderr, "<FAIL> cannot gen rt for load test\n" );
-                       }
-               } else {
-                       read_static_rt( ctx, 0 );               // not defined, just drive for that one case
+                       read_static_rt( ctx, 0 );
+                       rt = ctx->rtable;
+                       errors += fail_if_nil( rt, "read seed table didn't generate a rtable pointer in context" );
+                       unsetenv( "RMR_SEED_RT" );                              // remove for next test
                }
                }
+
+               read_static_rt( ctx, 0 );                       // drive for not there coverage
        }
 
        }
 
-       uta_fib( "no-suhch-file" );                     // drive some error checking for coverage
 
 
-/*
-       if( ctx ) {
-               if( ctx->rtg_addr ) {
-                       free( ctx->rtg_addr );
-               }
-               free( ctx );
+       buf = uta_fib( "no-suhch-file" );                       // drive some error checking for coverage
+       if( buf ) {
+               free( buf );
        }
        }
-*/
+
+
+       ep = (endpoint_t *) malloc( sizeof( *ep ) );
+       pthread_mutex_init( &ep->gate, NULL );
+       ep->name = strdup( "worm" );
+       ep->addr = NULL;
+       state = uta_link2( ep );
+       errors += fail_if_true( state, "link2 did not return false when given nil pointers" );
+
+       // ----------------- test the meid support for looking up an endpoint based on the meid in the message -----
+
+       ctx->my_name = strdup( "my_host_name" );                // set up to load a rtable
+       ctx->my_ip = strdup( "192.168.1.30" );
+       gen_rt( ctx );                                                                  // generate a route table with meid entries and hang off ctx
+
+       mbuf = rmr_alloc_msg( ctx, 2048 );               //  buffer to play with
+       mbuf->len = 100;
+       rmr_str2meid( mbuf, "meid1" );                                  // id that we know is in the map
+
+       ep = NULL;                                                                              // force to nil so we see it go non-nil
+       state = epsock_meid( ctx->rtable, mbuf, &nn_sock, &ep );
+       errors += fail_if_nil( ep, "ep was nil when looking up ep with known meid in message" );
+       errors += fail_not_equal( state, 1, "state was not true when looking up ep with known meid in message" );
+
+       rmr_str2meid( mbuf, "XXXmeid1" );                               // id that we know is NOT in the map
+       state = epsock_meid( ctx->rtable, mbuf, &nn_sock, &ep );
+       // it is NOT a valid check to test ep for nil -- epsock_mied doesn't guarentee ep is set/cleared when state is false
+       errors += fail_not_equal( state, 0, "state was not false when looking up ep with unknown meid in message" );
 
        return !!errors;                        // 1 or 0 regardless of count
 }
 
        return !!errors;                        // 1 or 0 regardless of count
 }