Correct table clear bug in route table ready
[ric-plt/lib/rmr.git] / test / rt_static_test.c
1 // : vi ts=4 sw=4 noet :
2 /*
3 ==================================================================================
4             Copyright (c) 2019 Nokia
5             Copyright (c) 2018-2019 AT&T Intellectual Property.
6
7    Licensed under the Apache License, Version 2.0 (the "License");
8    you may not use this file except in compliance with the License.
9    You may obtain a copy of the License at
10
11            http://www.apache.org/licenses/LICENSE-2.0
12
13    Unless required by applicable law or agreed to in writing, software
14    distributed under the License is distributed on an "AS IS" BASIS,
15    WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
16    See the License for the specific language governing permissions and
17    limitations under the License.
18 ==================================================================================
19 */
20
21 /*
22         Mmemonic:       rt_static_test.c
23         Abstract:       Test the route table funcitons. These are meant to be included at compile
24                                 time by the test driver.
25
26         Author:         E. Scott Daniels
27         Date:           3 April 2019
28 */
29
30 #include <unistd.h>
31 #include <stdio.h>
32 #include <stdlib.h>
33 #include <strings.h>
34 #include <errno.h>
35 #include <string.h>
36 #include <stdint.h>
37 #include <pthread.h>
38 #include <semaphore.h>
39
40 #include "rmr.h"
41 #include "rmr_agnostic.h"
42
43 typedef struct entry_info {
44         int group;
45         char* ep_name;
46 } ei_t;
47
48
49 /*
50         Driven by symtab foreach element of one space.
51         We count using the data as a counter.
52 */
53 static 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 */
66 static 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 /*
82         Builds a route table key.
83 */
84 static 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
90 fprintf( stderr, "<INFO> build key: %x %x --> %llx\n", (int) mtype, (int) sid, (long long) k );
91         return k;
92 }
93
94 /*
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
97         situations).
98 */
99 static int rt_test( ) {
100         uta_ctx_t* ctx;                 // context needed to test load static rt
101         uta_ctx_t* pctx;                // "private" context for route manager communication tests
102         route_table_t* rt;              // route table
103         route_table_t* crt;             // cloned route table
104         rtable_ent_t*   rte;    // route table entries from table
105         rtable_ent_t*   rte2;
106         endpoint_t*     ep;                     // endpoint added
107         endpoint_t*     ep2;
108         int more = 0;                   // more flag from round robin
109         int errors = 0;                 // number errors found
110         int     i;
111         int k;
112         int     c1;                                     // general counters
113         int c2;
114         int mtype;
115         int value;
116         int alt_value;
117         ei_t    entries[50];    // end point information
118         int             gcounts[7];             // number of groups in this set
119         int             ecounts[7];             // number of elements per group
120         uint64_t        mtypes[7];      // mtype/sid 'key' in the modern RMR world
121         char*   tok;
122         char*   nxt_tok;
123         int             enu = 0;
124         int             state;
125         char    *buf;
126         char    *buf2;
127         char*   seed_fname;             // seed file
128         SOCKET_TYPE     nn_sock;        // differnt in each transport (nng == struct, SI/Nano == int)
129         rmr_mbuf_t*     mbuf;           // message for meid route testing
130         void*   p;                              // generic pointer
131
132         #ifndef NNG_UNDER_TEST
133                 si_ctx_t* si_ctx = NULL;
134         #endif
135
136         setenv( "ENV_VERBOSE_FILE", ".ut_rmr_verbose", 1 );                     // allow for verbose code in rtc to be driven
137         i = open( ".ut_rmr_verbose", O_RDWR | O_CREAT, 0644 );
138         if( i >= 0 ) {
139                 write( i, "2\n", 2 );
140                 close( i );
141         }
142
143
144         /*
145                 The hacky code below calls the necessary rmr functions to create a route table
146                 as though the following were read and parsed by the rmr functions. (This tests
147                 the individual funcitons and avoids writing another parser, so it's not pretty.)
148
149                 mse | 0 | 0 | yahoo.com:4561,localhost:4562
150                 mse | 1 | 0 | localhost:4560,localhost:4568,localhost:4569; localhost:4561,localhost:4562
151                 mse | 2 | 0 | localhost:4563,localhost:4564
152                 mse | 3 | 0 | localhost:4565
153                 mse | 3 | 11 | locahost:5511
154                 mse | 3 | -1 | localhost:5500
155         */
156         gcounts[0] = 1;                                                 // first entry has 1 group with 2 endpoints; message type 0, sid 0
157         ecounts[0] = 2;
158         mtypes[0] = build_key( 0, 0 );                  // mtype is now a key of mtype/sid
159         entries[enu].group = 0; entries[enu].ep_name = "yahoo.com:4561"; enu++;         // use a dns resolvable name to test that
160         entries[enu].group = 0; entries[enu].ep_name = "localhost:4562"; enu++;         // rest can default to some dummy ip
161
162         gcounts[1] = 2;                         // 2 groups
163         ecounts[1] = 3;                         // first has 3 endpoints
164         mtypes[1] = build_key( 1, 0 );
165         entries[enu].group = 0; entries[enu].ep_name = "localhost:4560"; enu++;
166         entries[enu].group = 0; entries[enu].ep_name = "localhost:4568"; enu++;
167         entries[enu].group = 0; entries[enu].ep_name = "localhost:4569"; enu++;
168
169         gcounts[2] = 0;                                 // 0 means use same rte, this is the next group for the entry
170         ecounts[2] = 2;                                 // 2 endpoints
171         mtypes[2] = 999;                                // ignored when appending to previous entry
172         entries[enu].group = 1; entries[enu].ep_name = "localhost:4561"; enu++;
173         entries[enu].group = 1; entries[enu].ep_name = "localhost:4562"; enu++;
174
175         gcounts[3] = 1;                                 // next entry has 1 group
176         ecounts[3] = 2;                                 // with 2 enpoints
177         mtypes[3] = build_key( 2, 0 );
178         entries[enu].group = 0; entries[enu].ep_name = "localhost:4563"; enu++;
179         entries[enu].group = 0; entries[enu].ep_name = "localhost:4564"; enu++;
180
181         gcounts[4] = 1;                                 // three entries for mt==3 with different sids
182         ecounts[4] = 1;
183         mtypes[4] = build_key( 3, 0 );
184         entries[enu].group = 0; entries[enu].ep_name = "localhost:5500"; enu++;
185
186         gcounts[5] = 1;
187         ecounts[5] = 1;
188         mtypes[5] = build_key( 3, 11 );
189         entries[enu].group = 0; entries[enu].ep_name = "localhost:5511"; enu++;
190
191         gcounts[6] = 1;
192         ecounts[6] = 1;
193         mtypes[6] = build_key( 3, -1 );
194         entries[enu].group = 0; entries[enu].ep_name = "localhost:5512"; enu++;
195
196
197         rt = uta_rt_init( NULL );
198         errors += fail_if_false( rt == NULL, "rt_init given a nil context didn't return nil" );
199
200         ctx = mk_dummy_ctx();           // make a dummy with rtgate mutex
201         rt = uta_rt_init( ctx );                                                                                // get us a route table
202         if( (errors += fail_if_nil( rt, "pointer to route table" )) ) {
203                 fprintf( stderr, "<FAIL> abort: cannot continue without a route table\n" );
204                 exit( 1 );
205         }
206
207         enu = 0;
208         rte = NULL;
209         for( i = 0; i < sizeof( gcounts )/sizeof( int ); i++ ) {                                // add entries defined above
210                 if( gcounts[i] ) {
211                         rte = uta_add_rte( rt, mtypes[i], gcounts[i] );                                 // get/create entry for message type
212                         if( (errors += fail_if_nil( rte, "route table entry" )) ) {
213                                 fprintf( stderr, "<FAIL> abort: cannot continue without a route table entry\n" );
214                                 exit( 1 );
215                         }
216                 } else {
217                         if( rte == NULL ) {
218                                 fprintf( stderr, "<SNAFU> internal testing error -- rte was nil for gcount == 0\n" );
219                                 exit( 1 );
220                         }
221                 }
222
223                 for( k = 0; k < ecounts[i]; k++ ) {
224                         ep = uta_add_ep( rt, rte, entries[enu].ep_name, entries[enu].group );
225                         errors += fail_if_nil( ep, "endpoint" );
226                         enu++;
227                 }
228         }
229
230         // ----- end hacking together a route table ---------------------------------------------------
231
232
233         crt = uta_rt_clone( ctx, rt, NULL, 0 );                                                         // create a new rt and clone only the me entries
234         errors += fail_if_nil( crt, "cloned route table" );
235         if( crt ) {
236                 c1 = count_entries( rt, 1 );
237                 c2 = count_entries( crt, 1 );
238                 errors += fail_not_equal( c1, c2, "cloned (endpoints) table entries space 1 count (b) did not match original table count (a)" );
239
240                 c2 = count_entries( crt, 0 );
241                 errors += fail_not_equal( c2, 0, "cloned (endpoints) table entries space 0 count (a) was not zero as expected" );
242
243                 errors += fail_if_false( crt->ephash == rt->ephash, "ephash pointer in cloned table is not right" );
244                 uta_rt_drop( crt );
245         }
246
247
248         crt = uta_rt_clone( ctx, rt, NULL, 1 );                                                 // clone all entries (MT and ME)
249         errors += fail_if_nil( crt, "cloned (all) route table" );
250
251         if( crt ) {
252                 c1 = count_entries( rt, 0 );
253                 c2 = count_entries( crt, 0 );
254                 errors += fail_not_equal( c1, c2, "cloned (all) table entries space 0 count (b) did not match original table count (a)" );
255
256                 c1 = count_entries( rt, 1 );
257                 c2 = count_entries( crt, 1 );
258                 errors += fail_not_equal( c1, c2, "cloned (all) table entries space 1 count (b) did not match original table count (a)" );
259
260                 errors += fail_if_false( crt->ephash == rt->ephash, "ephash pointer in cloned table (all) is not right" );
261                 uta_rt_drop( crt );
262         }
263
264         #ifdef NNG_UNDER_TEST
265                 if( (ctx = (uta_ctx_t *) malloc( sizeof( uta_ctx_t ) )) != NULL ) {             // get a "context" needed for si testing
266                         memset( ctx, 0, sizeof( *ctx ) );
267                         ctx->rtable = rt;
268                 } else {
269                         fprintf( stderr, "<FAIL> cannot acllocate a context, cannot continue rtable tests\n" );
270                         return errors;
271                 }
272         #else
273                 ctx = mk_dummy_ctx();
274         #endif
275
276         ctx->rtable = rt;
277
278         ep = uta_get_ep( rt, "localhost:4561" );
279         errors += fail_if_nil( ep, "end point (fetch by name)" );
280         ep = uta_get_ep( rt, "bad_name:4560" );
281         errors += fail_not_nil( ep, "end point (fetch by name with bad name)" );
282
283         ep = NULL;
284         #ifdef NNG_UNDER_TEST
285                 state = uta_epsock_byname( rt, "localhost:4561", &nn_sock, &ep );               // this should be found
286         #else
287                 state = uta_epsock_byname( ctx, "localhost:4561", &nn_sock, &ep );              // this should be found
288         #endif
289         errors += fail_if_equal( state, 0, "socket (by name)" );
290         errors += fail_if_nil( ep, "epsock_byname did not populate endpoint pointer when expected to" );
291         //alt_value = uta_epsock_byname( rt, "localhost:4562" );                        // we might do a memcmp on the two structs, but for now nothing
292         //errors += fail_if_equal( value, alt_value, "app1/app2 sockets" );
293
294         #if  NNG_UNDER_TEST
295                 state = uta_epsock_byname( NULL, "localhost:4561", &nn_sock, &ep );             // test coverage on nil checks
296         #else
297                 state = uta_epsock_byname( NULL, "localhost:4561", &nn_sock, &ep );
298                 errors += fail_not_equal( state, 0, "socket (by name) nil context check returned true" );
299
300                 p = ctx->si_ctx;
301                 ctx->si_ctx = NULL;             // set to drive second test
302                 state = uta_epsock_byname( ctx, "localhost:4561", &nn_sock, &ep );
303                 ctx->si_ctx = p;
304         #endif
305         errors += fail_not_equal( state, 0, "socket (by name) nil check returned true" );
306
307         if( ep ) {                                      // if previous test fails, cant run this
308                 ep->open = 1;
309                 #if  NNG_UNDER_TEST
310                         state = uta_epsock_byname( rt, "localhost:4561", &nn_sock, NULL );              // test coverage on nil checks
311                 #else
312                         state = uta_epsock_byname( ctx, "localhost:4561", &nn_sock, NULL );
313                 #endif
314                 errors += fail_if_equal( state, 0, "socket (by name) open ep check returned false" );
315         }
316
317
318         // --- test that the get_rte function finds expected keys, and retries to find 'bad' sid attempts for valid mtypes with no sid
319         rte = uta_get_rte( rt, 0, 1, TRUE );                    // s=0 m=1 is defined, so this should return a pointer
320         errors += fail_if_nil( rte, "get_rte did not return a pointer when s=0 m=1 true given" );
321
322         rte = uta_get_rte( rt, 0, 1, FALSE );                   // the retry shouldn't apply, but ensure it does the righ thing
323         errors += fail_if_nil( rte, "get_rte did not return a pointer when s=0 m=1 false given" );
324
325         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
326         errors += fail_not_nil( rte, "get_rte returned a pointer when s=1000 m=1 false given" );
327
328         rte = uta_get_rte( rt, 1000, 1, TRUE );                 // this should also fail as there is no mt==1 sid==-1 defined
329         errors += fail_not_nil( rte, "get_rte returned a pointer when s=1000 m=1 true given" );
330
331         rte = uta_get_rte( rt, 0, 3, TRUE );                    // mtype sid combo does exist; true/false should not matter
332         errors += fail_if_nil( rte, "get_rte did not return a pointer when s=0 m=3 true given" );
333
334         rte2 = uta_get_rte( rt, 11, 3, TRUE );                  // same mtype as before, different (valid) group, rte should be different than before
335         errors += fail_if_nil( rte2, "get_rte did not return a pointer when s=11 m=3 true given" );
336         errors += fail_if_true( rte == rte2, "get_rte for mtype==3 and different sids (0 and 11) returned the same rte pointer" );
337
338         rte2 = uta_get_rte( rt, 0, 3, FALSE );                  // since the mtype/sid combo exists, setting false should return the same as before
339         errors += fail_if_nil( rte2, "get_rte did not return a pointer when s=0 m=3 false given" );
340         errors += fail_if_false( rte == rte2, "get_rte did not return same pointer when mtype/sid combo given with different true/false" );
341
342         rte = uta_get_rte( rt, 12, 3, FALSE );                  // this combo does not exist and should fail when alt-key is not allowed (false)
343         errors += fail_not_nil( rte, "get_rte returned a pointer for s=12, m=3, false" );
344
345         rte = uta_get_rte( rt, 12, 3, TRUE );                   // this should return the entry for the 3/-1 combination
346         errors += fail_if_nil( rte, "get_rte did not return a pointer for s=12, m=3, true" );
347
348
349         alt_value = -1;
350         rte = uta_get_rte( rt, 0, 1, FALSE );                   // get an rte for the next loop
351         if( rte ) {
352                 for( i = 0; i < 10; i++ ) {                                                                     // round robin return value should be different each time
353                         #ifdef NNG_UNDER_TEST
354                                 value = uta_epsock_rr( rte, 0, &more, &nn_sock, &ep );          // msg type 1, group 1
355                         #else
356                                 value = uta_epsock_rr( ctx, rte, 0, &more, &nn_sock, &ep );
357                         #endif
358
359                         errors += fail_if_equal( value, alt_value, "round robiin sockets with multiple end points" );
360                         errors += fail_if_false( more, "more for mtype==1" );
361                         alt_value = value;
362                 }
363         }
364
365         more = -1;
366         rte = uta_get_rte( rt, 0, 3, FALSE );                           // get an rte for the next loop
367         if( rte ) {
368                 for( i = 0; i < 10; i++ ) {                                                             // this mtype has only one endpoint, so rr should be same each time
369                         #ifdef NNG_UNDER_TEST
370                                 value = uta_epsock_rr( rte, 0, NULL, &nn_sock, &ep );           // also test ability to deal properly with nil more pointer
371                         #else
372                                 value = uta_epsock_rr( ctx, rte, 0, NULL, &nn_sock, &ep );
373                         #endif
374
375                         if( i ) {
376                                 errors += fail_not_equal( value, alt_value, "round robin sockets with one endpoint" );
377                                 errors += fail_not_equal( more, -1, "more value changed in single group instance" );
378                         }
379                         alt_value = value;
380                 }
381         }
382
383         rte = uta_get_rte( rt, 11, 3, TRUE );
384         #ifdef NNG_UNDER_TEST
385                 state = uta_epsock_rr( rte, 22, NULL, NULL, &ep );
386         #else
387                 state = uta_epsock_rr( ctx, rte, 22, NULL, NULL, &ep );
388         #endif
389         errors += fail_if_true( state, "uta_epsock_rr returned bad (non-zero) state when given nil socket pointer" );
390
391
392         uta_rt_clone( ctx, NULL, NULL, 0 );                                                             // verify null parms don't crash things
393         uta_rt_drop( NULL );
394         #ifdef NNG_UNDER_TEST
395                 uta_epsock_rr( NULL, 0,  &more, &nn_sock, &ep );                        // drive null case for coverage
396                 state = uta_epsock_rr( rte, 22, NULL, NULL, &ep );
397         #else
398                 state = uta_epsock_rr( NULL, NULL, 0,  &more, &nn_sock, &ep );                  // drive null case for coverage
399                 errors += fail_not_equal( state, 0, "uta_epsock_rr did not return false when given nil ctx" );
400
401                 state = uta_epsock_rr( ctx, NULL, 0,  &more, &nn_sock, &ep );
402                 errors += fail_not_equal( state, 0, "uta_epsock_rr did not return false when given nil rte" );
403
404                 state = uta_epsock_rr( ctx, rte, 10000,  &more, &nn_sock, &ep );
405                 errors += fail_not_equal( state, 0, "uta_epsock_rr did not return false when given invalid group number" );
406         #endif
407         uta_add_rte( NULL, 99, 1 );
408         uta_get_rte( NULL, 0, 1000, TRUE );
409
410         fprintf( stderr, "[INFO] test: adding end points with nil data; warnings expected\n" );
411         uta_add_ep( NULL, NULL, "foo", 1 );
412         uta_add_ep( rt, NULL, "foo", 1 );
413
414         buf = uta_fib( ".gitignore" );
415         errors += fail_if_nil( buf, "buffer from read file into buffer" );
416         if( buf ) {
417                 free( buf );
418         }
419         buf = uta_fib( "no-file" );
420         errors += fail_if_nil( buf, "buffer from read file into buffer (no file)" );
421         if( buf ) {
422                 free( buf );
423         }
424
425         fprintf( stderr, "<INFO> test is overtly dropping rt table at %p\n", rt );
426         ctx->rtable = NULL;
427         uta_rt_drop( rt );
428         rt = NULL;
429
430
431         // --- force the load of a RT which has some edge case forcing issues
432         if( ctx ) {
433                 char*   rt_stuff =
434                                 "newrt | start | dummy-seed\n"
435                                 "mse | 1  | -1 | localhost:84306\n"
436                                 "mse | 10  | -1 | localhost:84306\n"
437                                 "mse | 10  | 1 | localhost:84306\n"
438                                 "# should cause failure because there aren't 10 entries above\n"
439                                 "newrt | end | 10\n"
440
441                                 "# this table has no end\n"
442                                 "newrt | start | dummy-seed\n"
443                                 "mse | 1  | -1 | localhost:84306\n"
444                                 "mse | 10  | -1 | localhost:84306\n"
445                                 "mse | 10  | 1 | localhost:84306\n"
446
447                                 "# this table should be ok\n"
448                                 "newrt | start | dummy-seed\n"
449                                 "mse | 1  | -1 | localhost:84306\n"
450                                 "mse | 10  | -1 | localhost:84306\n"
451                                 "mse | 10  | 1 | localhost:84306\n"
452                                 "newrt | end | 3\n"
453
454                                 "# for an update to the existing table\n"
455                                 "# not in progress; drive that exception check\n"
456                                 "update | end | 23\n"
457
458                                 "update | start | dummy-seed\n"
459                                 "mse | 3 | 2 | localhost:2222\n"
460                                 "# short record to drive test\n"
461                                 "del\n"
462                                 "# no table end for exception handling\n"
463
464                                 "update | start | dummy-seed\n"
465                                 "mse | 2 | 2 | localhost:2222\n"
466                                 "del | 10 | 1\n"
467                                 "update | end | 2\n";
468
469                 fprintf( stderr, "<INFO> loading RT from edge case static table\n" );
470                 fprintf( stderr, "<INFO> %s\n", rt_stuff );
471                 gen_custom_rt( ctx, rt_stuff );
472                 fprintf( stderr, "<INFO> edge case load completed\n" );
473                 errors += fail_if_nil( ctx->rtable, "edge case route table didn't generate a pointer into the context" );
474
475                 unsetenv( "RMR_SEED_RT" );                      // remove for next read try
476                 read_static_rt( ctx, 0 );                       // drive for not there coverage
477         }
478
479
480         buf = uta_fib( "no-suhch-file" );                       // drive some error checking for coverage
481         if( buf ) {
482                 free( buf );
483         }
484
485
486         ep = (endpoint_t *) malloc( sizeof( *ep ) );
487         memset( ep, 0, sizeof( ep ) );
488         pthread_mutex_init( &ep->gate, NULL );
489         ep->name = strdup( "worm" );
490         ep->addr = NULL;
491         ep->notify = 1;
492         #ifdef NNG_UNDER_TEST
493                 state = uta_link2( ep );
494         #else
495                 state = uta_link2( ctx, ep );
496         #endif
497         errors += fail_if_true( state, "link2 did not return false when given a bad target name" );
498
499         #ifdef NNG_UNDER_TEST
500                 state = uta_link2( NULL );
501         #else
502                 state = uta_link2( ctx, NULL );
503                 errors += fail_if_true( state, "link2 did not return false when given nil ep pointer" );
504
505                 state = uta_link2( NULL, ep );
506         #endif
507         errors += fail_if_true( state, "link2 did not return false when given nil pointer" );
508
509         ep->name = strdup( "localhost:5512" );
510         ep->open = 1;
511         #ifdef NNG_UNDER_TEST
512                 state = uta_link2( ep );                        // drive for coverage
513         #else
514                 state = uta_link2( ctx, ep );
515         #endif
516         errors += fail_if_false( state, "link2 did returned false when given open ep" );
517
518         #ifndef NNG_UNDER_TEST
519                 ep->open = 0;                                                   // context is used only if ep not open, so to check this test close the ep
520                 ep->notify = 1;
521                 state = rt_link2_ep( NULL, ep );
522                 errors += fail_if_true( state, "rt_link2_ep returned true when given bad context" );
523
524                 state = rt_link2_ep( ctx, NULL );
525                 errors += fail_if_true( state, "rt_link2_ep returned true when given bad ep" );
526
527                 ep->open = 1;
528                 state = rt_link2_ep( ctx, ep );
529                 errors += fail_if_false( state, "rt_link2_ep returned false when given an open ep" );
530
531                 ep->open = 0;
532                 state = rt_link2_ep( ctx, ep );
533                 errors += fail_if_false( state, "rt_link2_ep returned false when given a closed ep" );
534
535                 ep->open = 1;
536                 uta_ep_failed( ep );
537                 errors += fail_if_true( ep->open, "uta_ep_failed didn't set open flag to false" );
538
539         #endif
540
541
542         // ----------------- test the meid support for looking up an endpoint based on the meid in the message -----
543
544         ctx->rtable = NULL;
545         ctx->my_name = strdup( "my_host_name" );                // set up to load a rtable
546         ctx->my_ip = strdup( "192.168.1.30" );
547         gen_rt( ctx );                                                                  // generate a route table with meid entries and hang off ctx
548
549         mbuf = rmr_alloc_msg( ctx, 2048 );               //  buffer to play with
550         mbuf->len = 100;
551         rmr_str2meid( mbuf, "meid1" );                                  // id that we know is in the map
552
553         #ifdef NNG_UNDER_TEST
554                 ep = NULL;                                                                              // force to nil so we see it go non-nil
555                 state = epsock_meid( ctx->rtable, mbuf, &nn_sock, &ep );
556                 errors += fail_if_nil( ep, "ep was nil when looking up ep with known meid in message" );
557                 errors += fail_not_equal( state, 1, "state was not true when looking up ep with known meid in message" );
558
559                 rmr_str2meid( mbuf, "XXXmeid1" );                               // id that we know is NOT in the map
560                 state = epsock_meid( ctx->rtable, mbuf, &nn_sock, &ep );
561                 // it is NOT a valid check to test ep for nil -- epsock_mied doesn't guarentee ep is set/cleared when state is false
562                 errors += fail_not_equal( state, 0, "state was not false when looking up ep with unknown meid in message" );
563         #else
564                 ep = NULL;                                                                              // force to nil so we see it go non-nil
565                 state = epsock_meid( ctx, ctx->rtable,  mbuf, &nn_sock, &ep );
566                 errors += fail_if_nil( ep, "ep was nil when looking up ep with known meid in message" );
567                 errors += fail_not_equal( state, 1, "state was not true when looking up ep with known meid in message" );
568
569                 state = epsock_meid( ctx, ctx->rtable,  mbuf, &nn_sock, &ep );          // a second call to drive open == true check for coverage
570                 errors += fail_if_nil( ep, "ep was nil when looking up ep with known meid in message; on open ep" );
571                 errors += fail_not_equal( state, 1, "state was not true when looking up ep with known meid in message; on open ep" );
572
573                 rmr_str2meid( mbuf, "XXXmeid1" );                               // id that we know is NOT in the map
574                 state = epsock_meid( ctx, ctx->rtable, mbuf, &nn_sock, &ep );
575                 // it is NOT a valid check to test ep for nil -- epsock_mied doesn't guarentee ep is set/cleared when state is false
576                 errors += fail_not_equal( state, 0, "state was not false when looking up ep with unknown meid in message" );
577
578                 state = epsock_meid( NULL, ctx->rtable,  mbuf, &nn_sock, &ep );
579                 errors += fail_not_equal( state, 0, "epsock_meid returned true when given nil context" );
580
581                 state = epsock_meid( ctx, ctx->rtable,  mbuf, NULL, &ep );
582                 errors += fail_not_equal( state, 0, "epsock_meid returned true when given nil socket pointer" );
583         #endif
584
585         // ------------  debugging and such; coverage only calls ----------------------------------------------------------
586                 ep_stats( ctx->rtable, NULL, "name", NULL, NULL );                      // ensure no crash when given nil pointer
587                 rt_epcounts( ctx->rtable, "testing" );
588                 rt_epcounts( NULL, "testing" );
589
590                 buf = ensure_nlterm( NULL );
591                 errors += fail_if_nil( buf, "ensure nlterm returned null pointer when given nil ptr" );
592                 if( buf ) {
593                         errors += fail_not_equal( strlen( buf ), 1, "ensure nlterm returned incorrect length string when given nil pointer" );
594                         free( buf );
595                 }
596
597                 buf = ensure_nlterm( strdup( "x" ) );                   // should return "x\n"
598                 errors += fail_if_nil( buf, "ensure nlterm returned null pointer when given single char string" );
599                 if( buf ) {
600                         errors += fail_not_equal( strlen( buf ), 2, "ensure nlterm returned incorrect length string when given single char string" );
601                         free( buf );
602                 }
603
604                 buf = strdup( "x\n" );
605                 buf2 = ensure_nlterm( buf );                                    // buffer returned should be the same
606                 if( fail_not_pequal( buf, buf2, "ensure nlterm returned new buffer for one char string with newline" ) ) {
607                         errors++;
608                         free( buf2 );
609                 }
610                 free( buf );
611
612                 buf = strdup( "Missing our trips to Gloria's for papossas.\n" );
613                 buf2 = ensure_nlterm( buf );                                                                                    // buffer returned should be the same
614                 if( fail_not_pequal( buf, buf2, "ensure nlterm returned new buffer for string with newline" ) ) {
615                         errors++;
616                         free( buf2 );
617                 }
618                 free( buf );
619
620                 buf = ensure_nlterm( strdup( "Stand up and cheer!" ) );                                 // force addition of newline
621                 if( buf ) {
622                         errors += fail_not_equal( strcmp( buf, "Stand up and cheer!\n" ), 0, "ensure nlterm didn't add newline" );
623                         free( buf );
624                         buf = NULL;
625                 }
626
627
628         // ------------- route manager request/response funcitons -------------------------------------------------------
629                 {
630                         rmr_mbuf_t*     smsg;
631
632                         smsg = rmr_alloc_msg( ctx, 1024 );
633                         send_rt_ack( ctx, smsg, "123456", 0, "no reason" );
634
635                         pctx = mk_dummy_ctx();
636                         ctx->rtg_whid = -1;
637                         state = send_update_req( pctx, ctx );
638                         errors += fail_not_equal( state, 0, "send_update_req did not return 0" );
639
640                         ctx->rtg_whid = rmr_wh_open( ctx, "localhost:19289" );
641                         state = send_update_req( pctx, ctx );
642                         errors += fail_if_equal( state, 0, "send_update_req to an open whid did not return 0" );
643                 }
644
645
646         // ------------- si only; fd to ep conversion functions ---------------------------------------------------------
647         #ifndef NNG_UNDER_TEST
648                 ep2 = (endpoint_t *) malloc( sizeof( *ep ) );
649
650                 fd2ep_init( ctx );
651                 fd2ep_add( ctx, 10, ep2 );
652
653                 ep = fd2ep_get( ctx, 10 );
654                 errors += fail_if_nil( ep, "fd2ep did not return pointer for known mapping" );
655                 errors += fail_if_false( ep == ep2,  "fd2ep did not return same pointer that was added" );
656
657                 ep = fd2ep_get( ctx, 20 );
658                 errors += fail_not_nil( ep, "fd2ep did returned a pointer for unknown mapping" );
659
660                 ep = fd2ep_del( ctx, 10 );
661                 errors += fail_if_nil( ep, "fd2ep delete did not return pointer for known mapping" );
662                 errors += fail_if_false( ep == ep2,  "fd2ep delete did not return same pointer that was added" );
663
664                 ep = fd2ep_del( ctx, 20 );
665                 errors += fail_not_nil( ep, "fd2ep delete returned a pointer for unknown mapping" );
666         #endif
667
668         // ---------------- misc coverage tests --------------------------------------------------------------------------
669                 collect_things( NULL, NULL, NULL, NULL, NULL );                         // these both return null, these test NP checks
670                 collect_things( NULL, NULL, NULL, NULL, (void *) 1234 );                // the last is an invalid pointer, but check needed to force check on previous param
671                 del_rte( NULL, NULL, NULL, NULL, NULL );
672
673         return !!errors;                        // 1 or 0 regardless of count
674 }