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