Correct table clear bug in route table ready
[ric-plt/lib/rmr.git] / test / rt_static_test.c
index ce0eb25..79d0561 100644 (file)
 #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;
@@ -44,6 +46,51 @@ typedef struct entry_info {
 } 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
@@ -51,69 +98,107 @@ typedef struct entry_info {
 */
 static int rt_test( ) {
        uta_ctx_t* ctx;                 // context needed to test load static rt
+       uta_ctx_t* pctx;                // "private" context for route manager communication tests
        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
+       endpoint_t*     ep2;
        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             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;
        int             state;
        char    *buf;
+       char    *buf2;
        char*   seed_fname;             // seed file
-       nng_socket nn_sock;             // this is a struct in nng, so difficult to validate
+       SOCKET_TYPE     nn_sock;        // differnt in each transport (nng == struct, SI/Nano == int)
+       rmr_mbuf_t*     mbuf;           // message for meid route testing
+       void*   p;                              // generic pointer
+
+       #ifndef NNG_UNDER_TEST
+               si_ctx_t* si_ctx = NULL;
+       #endif
 
        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 );
        }
 
-       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;
-       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 = "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++;
 
-       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++;
 
-       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++;
 
-       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;
-       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( NULL );
+       errors += fail_if_false( rt == NULL, "rt_init given a nil context didn't return nil" );
+
+       ctx = mk_dummy_ctx();           // make a dummy with rtgate mutex
+       rt = uta_rt_init( ctx );                                                                                // get us a route table
        if( (errors += fail_if_nil( rt, "pointer to route table" )) ) {
                fprintf( stderr, "<FAIL> abort: cannot continue without a route table\n" );
                exit( 1 );
@@ -142,44 +227,185 @@ static int rt_test( ) {
                }
        }
 
-       crt = uta_rt_clone( rt );
+       // ----- end hacking together a route table ---------------------------------------------------
+
+
+       crt = uta_rt_clone( ctx, rt, NULL, 0 );                                                         // create a new rt and clone only the me entries
        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" );
+
+               errors += fail_if_false( crt->ephash == rt->ephash, "ephash pointer in cloned table is not right" );
+               uta_rt_drop( crt );
+       }
+
+
+       crt = uta_rt_clone( ctx, rt, NULL, 1 );                                                 // clone all entries (MT and ME)
+       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)" );
+
+               errors += fail_if_false( crt->ephash == rt->ephash, "ephash pointer in cloned table (all) is not right" );
+               uta_rt_drop( crt );
+       }
+
+       #ifdef NNG_UNDER_TEST
+               if( (ctx = (uta_ctx_t *) malloc( sizeof( uta_ctx_t ) )) != NULL ) {             // get a "context" needed for si testing
+                       memset( ctx, 0, sizeof( *ctx ) );
+                       ctx->rtable = rt;
+               } else {
+                       fprintf( stderr, "<FAIL> cannot acllocate a context, cannot continue rtable tests\n" );
+                       return errors;
+               }
+       #else
+               ctx = mk_dummy_ctx();
+       #endif
+
+       ctx->rtable = rt;
 
        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;
+       #ifdef NNG_UNDER_TEST
+               state = uta_epsock_byname( rt, "localhost:4561", &nn_sock, &ep );               // this should be found
+       #else
+               state = uta_epsock_byname( ctx, "localhost:4561", &nn_sock, &ep );              // this should be found
+       #endif
        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" );
 
+       #if  NNG_UNDER_TEST
+               state = uta_epsock_byname( NULL, "localhost:4561", &nn_sock, &ep );             // test coverage on nil checks
+       #else
+               state = uta_epsock_byname( NULL, "localhost:4561", &nn_sock, &ep );
+               errors += fail_not_equal( state, 0, "socket (by name) nil context check returned true" );
+
+               p = ctx->si_ctx;
+               ctx->si_ctx = NULL;             // set to drive second test
+               state = uta_epsock_byname( ctx, "localhost:4561", &nn_sock, &ep );
+               ctx->si_ctx = p;
+       #endif
+       errors += fail_not_equal( state, 0, "socket (by name) nil check returned true" );
+
+       if( ep ) {                                      // if previous test fails, cant run this
+               ep->open = 1;
+               #if  NNG_UNDER_TEST
+                       state = uta_epsock_byname( rt, "localhost:4561", &nn_sock, NULL );              // test coverage on nil checks
+               #else
+                       state = uta_epsock_byname( ctx, "localhost:4561", &nn_sock, NULL );
+               #endif
+               errors += fail_if_equal( state, 0, "socket (by name) open ep check returned false" );
+       }
+
+
+       // --- 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;
-       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
+                       #ifdef NNG_UNDER_TEST
+                               value = uta_epsock_rr( rte, 0, &more, &nn_sock, &ep );          // msg type 1, group 1
+                       #else
+                               value = uta_epsock_rr( ctx, rte, 0, &more, &nn_sock, &ep );
+                       #endif
+
+                       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;
-       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
+                       #ifdef NNG_UNDER_TEST
+                               value = uta_epsock_rr( rte, 0, NULL, &nn_sock, &ep );           // also test ability to deal properly with nil more pointer
+                       #else
+                               value = uta_epsock_rr( ctx, rte, 0, NULL, &nn_sock, &ep );
+                       #endif
+
+                       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 );
+       #ifdef NNG_UNDER_TEST
+               state = uta_epsock_rr( rte, 22, NULL, NULL, &ep );
+       #else
+               state = uta_epsock_rr( ctx, rte, 22, NULL, NULL, &ep );
+       #endif
+       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_clone( ctx, NULL, NULL, 0 );                                                             // 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
+       #ifdef NNG_UNDER_TEST
+               uta_epsock_rr( NULL, 0,  &more, &nn_sock, &ep );                        // drive null case for coverage
+               state = uta_epsock_rr( rte, 22, NULL, NULL, &ep );
+       #else
+               state = uta_epsock_rr( NULL, NULL, 0,  &more, &nn_sock, &ep );                  // drive null case for coverage
+               errors += fail_not_equal( state, 0, "uta_epsock_rr did not return false when given nil ctx" );
+
+               state = uta_epsock_rr( ctx, NULL, 0,  &more, &nn_sock, &ep );
+               errors += fail_not_equal( state, 0, "uta_epsock_rr did not return false when given nil rte" );
+
+               state = uta_epsock_rr( ctx, rte, 10000,  &more, &nn_sock, &ep );
+               errors += fail_not_equal( state, 0, "uta_epsock_rr did not return false when given invalid group number" );
+       #endif
        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 );
@@ -196,47 +422,253 @@ static int rt_test( ) {
                free( buf );
        }
 
+       fprintf( stderr, "<INFO> test is overtly dropping rt table at %p\n", rt );
+       ctx->rtable = NULL;
        uta_rt_drop( rt );
+       rt = NULL;
 
-       uta_rt_drop( crt );
 
-       if( (ctx = (uta_ctx_t *) malloc( sizeof( uta_ctx_t ) )) != NULL ) {
-               memset( ctx, 0, sizeof( *ctx ) );
+       // --- force the load of a RT which has some edge case forcing issues
+       if( ctx ) {
+               char*   rt_stuff =
+                               "newrt | start | dummy-seed\n"
+                               "mse | 1  | -1 | localhost:84306\n"
+                               "mse | 10  | -1 | localhost:84306\n"
+                               "mse | 10  | 1 | localhost:84306\n"
+                               "# should cause failure because there aren't 10 entries above\n"
+                               "newrt | end | 10\n"
+
+                               "# this table has no end\n"
+                               "newrt | start | dummy-seed\n"
+                               "mse | 1  | -1 | localhost:84306\n"
+                               "mse | 10  | -1 | localhost:84306\n"
+                               "mse | 10  | 1 | localhost:84306\n"
+
+                               "# this table should be ok\n"
+                               "newrt | start | dummy-seed\n"
+                               "mse | 1  | -1 | localhost:84306\n"
+                               "mse | 10  | -1 | localhost:84306\n"
+                               "mse | 10  | 1 | localhost:84306\n"
+                               "newrt | end | 3\n"
+
+                               "# for an update to the existing table\n"
+                               "# not in progress; drive that exception check\n"
+                               "update | end | 23\n"
+
+                               "update | start | dummy-seed\n"
+                               "mse | 3 | 2 | localhost:2222\n"
+                               "# short record to drive test\n"
+                               "del\n"
+                               "# no table end for exception handling\n"
+
+                               "update | start | dummy-seed\n"
+                               "mse | 2 | 2 | localhost:2222\n"
+                               "del | 10 | 1\n"
+                               "update | end | 2\n";
+
+               fprintf( stderr, "<INFO> loading RT from edge case static table\n" );
+               fprintf( stderr, "<INFO> %s\n", rt_stuff );
+               gen_custom_rt( ctx, rt_stuff );
+               fprintf( stderr, "<INFO> edge case load completed\n" );
+               errors += fail_if_nil( ctx->rtable, "edge case route table didn't generate a pointer into the context" );
+
+               unsetenv( "RMR_SEED_RT" );                      // remove for next read try
+               read_static_rt( ctx, 0 );                       // drive for not there coverage
+       }
 
-               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
-               }
+
+       buf = uta_fib( "no-suhch-file" );                       // drive some error checking for coverage
+       if( buf ) {
+               free( buf );
        }
 
-       uta_fib( "no-suhch-file" );                     // drive some error checking for coverage
 
-/*
-       if( ctx ) {
-               if( ctx->rtg_addr ) {
-                       free( ctx->rtg_addr );
+       ep = (endpoint_t *) malloc( sizeof( *ep ) );
+       memset( ep, 0, sizeof( ep ) );
+       pthread_mutex_init( &ep->gate, NULL );
+       ep->name = strdup( "worm" );
+       ep->addr = NULL;
+       ep->notify = 1;
+       #ifdef NNG_UNDER_TEST
+               state = uta_link2( ep );
+       #else
+               state = uta_link2( ctx, ep );
+       #endif
+       errors += fail_if_true( state, "link2 did not return false when given a bad target name" );
+
+       #ifdef NNG_UNDER_TEST
+               state = uta_link2( NULL );
+       #else
+               state = uta_link2( ctx, NULL );
+               errors += fail_if_true( state, "link2 did not return false when given nil ep pointer" );
+
+               state = uta_link2( NULL, ep );
+       #endif
+       errors += fail_if_true( state, "link2 did not return false when given nil pointer" );
+
+       ep->name = strdup( "localhost:5512" );
+       ep->open = 1;
+       #ifdef NNG_UNDER_TEST
+               state = uta_link2( ep );                        // drive for coverage
+       #else
+               state = uta_link2( ctx, ep );
+       #endif
+       errors += fail_if_false( state, "link2 did returned false when given open ep" );
+
+       #ifndef NNG_UNDER_TEST
+               ep->open = 0;                                                   // context is used only if ep not open, so to check this test close the ep
+               ep->notify = 1;
+               state = rt_link2_ep( NULL, ep );
+               errors += fail_if_true( state, "rt_link2_ep returned true when given bad context" );
+
+               state = rt_link2_ep( ctx, NULL );
+               errors += fail_if_true( state, "rt_link2_ep returned true when given bad ep" );
+
+               ep->open = 1;
+               state = rt_link2_ep( ctx, ep );
+               errors += fail_if_false( state, "rt_link2_ep returned false when given an open ep" );
+
+               ep->open = 0;
+               state = rt_link2_ep( ctx, ep );
+               errors += fail_if_false( state, "rt_link2_ep returned false when given a closed ep" );
+
+               ep->open = 1;
+               uta_ep_failed( ep );
+               errors += fail_if_true( ep->open, "uta_ep_failed didn't set open flag to false" );
+
+       #endif
+
+
+       // ----------------- test the meid support for looking up an endpoint based on the meid in the message -----
+
+       ctx->rtable = NULL;
+       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
+
+       #ifdef NNG_UNDER_TEST
+               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" );
+       #else
+               ep = NULL;                                                                              // force to nil so we see it go non-nil
+               state = epsock_meid( ctx, 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" );
+
+               state = epsock_meid( ctx, ctx->rtable,  mbuf, &nn_sock, &ep );          // a second call to drive open == true check for coverage
+               errors += fail_if_nil( ep, "ep was nil when looking up ep with known meid in message; on open ep" );
+               errors += fail_not_equal( state, 1, "state was not true when looking up ep with known meid in message; on open ep" );
+
+               rmr_str2meid( mbuf, "XXXmeid1" );                               // id that we know is NOT in the map
+               state = epsock_meid( ctx, 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" );
+
+               state = epsock_meid( NULL, ctx->rtable,  mbuf, &nn_sock, &ep );
+               errors += fail_not_equal( state, 0, "epsock_meid returned true when given nil context" );
+
+               state = epsock_meid( ctx, ctx->rtable,  mbuf, NULL, &ep );
+               errors += fail_not_equal( state, 0, "epsock_meid returned true when given nil socket pointer" );
+       #endif
+
+       // ------------  debugging and such; coverage only calls ----------------------------------------------------------
+               ep_stats( ctx->rtable, NULL, "name", NULL, NULL );                      // ensure no crash when given nil pointer
+               rt_epcounts( ctx->rtable, "testing" );
+               rt_epcounts( NULL, "testing" );
+
+               buf = ensure_nlterm( NULL );
+               errors += fail_if_nil( buf, "ensure nlterm returned null pointer when given nil ptr" );
+               if( buf ) {
+                       errors += fail_not_equal( strlen( buf ), 1, "ensure nlterm returned incorrect length string when given nil pointer" );
+                       free( buf );
                }
-               free( ctx );
-       }
-*/
 
-       state = uta_link2( "worm", NULL, NULL );
-       errors += fail_if_true( state, "link2 did not return false when given nil pointers" );
+               buf = ensure_nlterm( strdup( "x" ) );                   // should return "x\n"
+               errors += fail_if_nil( buf, "ensure nlterm returned null pointer when given single char string" );
+               if( buf ) {
+                       errors += fail_not_equal( strlen( buf ), 2, "ensure nlterm returned incorrect length string when given single char string" );
+                       free( buf );
+               }
+
+               buf = strdup( "x\n" );
+               buf2 = ensure_nlterm( buf );                                    // buffer returned should be the same
+               if( fail_not_pequal( buf, buf2, "ensure nlterm returned new buffer for one char string with newline" ) ) {
+                       errors++;
+                       free( buf2 );
+               }
+               free( buf );
+
+               buf = strdup( "Missing our trips to Gloria's for papossas.\n" );
+               buf2 = ensure_nlterm( buf );                                                                                    // buffer returned should be the same
+               if( fail_not_pequal( buf, buf2, "ensure nlterm returned new buffer for string with newline" ) ) {
+                       errors++;
+                       free( buf2 );
+               }
+               free( buf );
+
+               buf = ensure_nlterm( strdup( "Stand up and cheer!" ) );                                 // force addition of newline
+               if( buf ) {
+                       errors += fail_not_equal( strcmp( buf, "Stand up and cheer!\n" ), 0, "ensure nlterm didn't add newline" );
+                       free( buf );
+                       buf = NULL;
+               }
+
+
+       // ------------- route manager request/response funcitons -------------------------------------------------------
+               {
+                       rmr_mbuf_t*     smsg;
+
+                       smsg = rmr_alloc_msg( ctx, 1024 );
+                       send_rt_ack( ctx, smsg, "123456", 0, "no reason" );
+
+                       pctx = mk_dummy_ctx();
+                       ctx->rtg_whid = -1;
+                       state = send_update_req( pctx, ctx );
+                       errors += fail_not_equal( state, 0, "send_update_req did not return 0" );
+
+                       ctx->rtg_whid = rmr_wh_open( ctx, "localhost:19289" );
+                       state = send_update_req( pctx, ctx );
+                       errors += fail_if_equal( state, 0, "send_update_req to an open whid did not return 0" );
+               }
+
+
+       // ------------- si only; fd to ep conversion functions ---------------------------------------------------------
+       #ifndef NNG_UNDER_TEST
+               ep2 = (endpoint_t *) malloc( sizeof( *ep ) );
+
+               fd2ep_init( ctx );
+               fd2ep_add( ctx, 10, ep2 );
+
+               ep = fd2ep_get( ctx, 10 );
+               errors += fail_if_nil( ep, "fd2ep did not return pointer for known mapping" );
+               errors += fail_if_false( ep == ep2,  "fd2ep did not return same pointer that was added" );
+
+               ep = fd2ep_get( ctx, 20 );
+               errors += fail_not_nil( ep, "fd2ep did returned a pointer for unknown mapping" );
+
+               ep = fd2ep_del( ctx, 10 );
+               errors += fail_if_nil( ep, "fd2ep delete did not return pointer for known mapping" );
+               errors += fail_if_false( ep == ep2,  "fd2ep delete did not return same pointer that was added" );
 
-       state = uta_epsock_rr( rt, 122, 0, NULL, NULL );
-       errors += fail_if_true( state, "uta_epsock_rr returned bad state when given nil socket pointer" );
+               ep = fd2ep_del( ctx, 20 );
+               errors += fail_not_nil( ep, "fd2ep delete returned a pointer for unknown mapping" );
+       #endif
 
-       rt = uta_rt_init( );                                                                            // get us a route table
-       state = uta_epsock_rr( rt, 0, -1, NULL, &nn_sock );
-       errors += fail_if_true( state, "uta_epsock_rr returned bad state (true) when given negative group number" );
+       // ---------------- misc coverage tests --------------------------------------------------------------------------
+               collect_things( NULL, NULL, NULL, NULL, NULL );                         // these both return null, these test NP checks
+               collect_things( NULL, NULL, NULL, NULL, (void *) 1234 );                // the last is an invalid pointer, but check needed to force check on previous param
+               del_rte( NULL, NULL, NULL, NULL, NULL );
 
        return !!errors;                        // 1 or 0 regardless of count
 }