Address complaints by code scanner
[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, ">>>>>> test is overtly dropping rt table at %p\n", rt );
419         uta_rt_drop( rt );
420         rt = NULL;
421
422
423         if( ctx ) {
424                 if( (seed_fname = getenv( "RMR_SEED_RT" )) != NULL ) {
425                         read_static_rt( ctx, 0 );
426                         rt = ctx->rtable;
427                         errors += fail_if_nil( rt, "read seed table didn't generate a rtable pointer in context" );
428                         unsetenv( "RMR_SEED_RT" );                              // remove for next test
429                 }
430
431                 read_static_rt( ctx, 0 );                       // drive for not there coverage
432         }
433
434
435         buf = uta_fib( "no-suhch-file" );                       // drive some error checking for coverage
436         if( buf ) {
437                 free( buf );
438         }
439
440
441         ep = (endpoint_t *) malloc( sizeof( *ep ) );
442         memset( ep, 0, sizeof( ep ) );
443         pthread_mutex_init( &ep->gate, NULL );
444         ep->name = strdup( "worm" );
445         ep->addr = NULL;
446         ep->notify = 1;
447         #ifdef NNG_UNDER_TEST
448                 state = uta_link2( ep );
449         #else
450                 state = uta_link2( ctx, ep );
451         #endif
452         errors += fail_if_true( state, "link2 did not return false when given a bad target name" );
453
454         #ifdef NNG_UNDER_TEST
455                 state = uta_link2( NULL );
456         #else
457                 state = uta_link2( ctx, NULL );
458                 errors += fail_if_true( state, "link2 did not return false when given nil ep pointer" );
459
460                 state = uta_link2( NULL, ep );
461         #endif
462         errors += fail_if_true( state, "link2 did not return false when given nil pointer" );
463
464         ep->name = strdup( "localhost:5512" );
465         ep->open = 1;
466         #ifdef NNG_UNDER_TEST
467                 state = uta_link2( ep );                        // drive for coverage
468         #else
469                 state = uta_link2( ctx, ep );
470         #endif
471         errors += fail_if_false( state, "link2 did returned false when given open ep" );
472
473         #ifndef NNG_UNDER_TEST
474                 ep->open = 0;                                                   // context is used only if ep not open, so to check this test close the ep
475                 ep->notify = 1;
476                 state = rt_link2_ep( NULL, ep );
477                 errors += fail_if_true( state, "rt_link2_ep returned true when given bad context" );
478
479                 state = rt_link2_ep( ctx, NULL );
480                 errors += fail_if_true( state, "rt_link2_ep returned true when given bad ep" );
481
482                 ep->open = 1;
483                 state = rt_link2_ep( ctx, ep );
484                 errors += fail_if_false( state, "rt_link2_ep returned false when given an open ep" );
485
486                 ep->open = 0;
487                 state = rt_link2_ep( ctx, ep );
488                 errors += fail_if_false( state, "rt_link2_ep returned false when given a closed ep" );
489
490                 ep->open = 1;
491                 uta_ep_failed( ep );
492                 errors += fail_if_true( ep->open, "uta_ep_failed didn't set open flag to false" );
493
494         #endif
495
496
497         // ----------------- test the meid support for looking up an endpoint based on the meid in the message -----
498
499         ctx->rtable = NULL;
500         ctx->my_name = strdup( "my_host_name" );                // set up to load a rtable
501         ctx->my_ip = strdup( "192.168.1.30" );
502         gen_rt( ctx );                                                                  // generate a route table with meid entries and hang off ctx
503
504         mbuf = rmr_alloc_msg( ctx, 2048 );               //  buffer to play with
505         mbuf->len = 100;
506         rmr_str2meid( mbuf, "meid1" );                                  // id that we know is in the map
507
508         #ifdef NNG_UNDER_TEST
509                 ep = NULL;                                                                              // force to nil so we see it go non-nil
510                 state = epsock_meid( ctx->rtable, mbuf, &nn_sock, &ep );
511                 errors += fail_if_nil( ep, "ep was nil when looking up ep with known meid in message" );
512                 errors += fail_not_equal( state, 1, "state was not true when looking up ep with known meid in message" );
513
514                 rmr_str2meid( mbuf, "XXXmeid1" );                               // id that we know is NOT in the map
515                 state = epsock_meid( ctx->rtable, mbuf, &nn_sock, &ep );
516                 // it is NOT a valid check to test ep for nil -- epsock_mied doesn't guarentee ep is set/cleared when state is false
517                 errors += fail_not_equal( state, 0, "state was not false when looking up ep with unknown meid in message" );
518         #else
519                 ep = NULL;                                                                              // force to nil so we see it go non-nil
520                 state = epsock_meid( ctx, ctx->rtable,  mbuf, &nn_sock, &ep );
521                 errors += fail_if_nil( ep, "ep was nil when looking up ep with known meid in message" );
522                 errors += fail_not_equal( state, 1, "state was not true when looking up ep with known meid in message" );
523
524                 state = epsock_meid( ctx, ctx->rtable,  mbuf, &nn_sock, &ep );          // a second call to drive open == true check for coverage
525                 errors += fail_if_nil( ep, "ep was nil when looking up ep with known meid in message; on open ep" );
526                 errors += fail_not_equal( state, 1, "state was not true when looking up ep with known meid in message; on open ep" );
527
528                 rmr_str2meid( mbuf, "XXXmeid1" );                               // id that we know is NOT in the map
529                 state = epsock_meid( ctx, ctx->rtable, mbuf, &nn_sock, &ep );
530                 // it is NOT a valid check to test ep for nil -- epsock_mied doesn't guarentee ep is set/cleared when state is false
531                 errors += fail_not_equal( state, 0, "state was not false when looking up ep with unknown meid in message" );
532
533                 state = epsock_meid( NULL, ctx->rtable,  mbuf, &nn_sock, &ep );
534                 errors += fail_not_equal( state, 0, "epsock_meid returned true when given nil context" );
535
536                 state = epsock_meid( ctx, ctx->rtable,  mbuf, NULL, &ep );
537                 errors += fail_not_equal( state, 0, "epsock_meid returned true when given nil socket pointer" );
538         #endif
539
540         // ------------  debugging and such; coverage only calls ----------------------------------------------------------
541                 ep_stats( ctx->rtable, NULL, "name", NULL, NULL );                      // ensure no crash when given nil pointer
542                 rt_epcounts( ctx->rtable, "testing" );
543                 rt_epcounts( NULL, "testing" );
544
545                 buf = ensure_nlterm( NULL );
546                 errors += fail_if_nil( buf, "ensure nlterm returned null pointer when given nil ptr" );
547                 if( buf ) {
548                         errors += fail_not_equal( strlen( buf ), 1, "ensure nlterm returned incorrect length string when given nil pointer" );
549                         free( buf );
550                 }
551
552                 buf = ensure_nlterm( strdup( "x" ) );                   // should return "x\n"
553                 errors += fail_if_nil( buf, "ensure nlterm returned null pointer when given single char string" );
554                 if( buf ) {
555                         errors += fail_not_equal( strlen( buf ), 2, "ensure nlterm returned incorrect length string when given single char string" );
556                         free( buf );
557                 }
558
559                 buf = strdup( "x\n" );
560                 buf2 = ensure_nlterm( buf );                                    // buffer returned should be the same
561                 if( fail_not_pequal( buf, buf2, "ensure nlterm returned new buffer for one char string with newline" ) ) {
562                         errors++;
563                         free( buf2 );
564                 }
565                 free( buf );
566
567                 buf = strdup( "Missing our trips to Gloria's for papossas.\n" );
568                 buf2 = ensure_nlterm( buf );                                                                                    // buffer returned should be the same
569                 if( fail_not_pequal( buf, buf2, "ensure nlterm returned new buffer for string with newline" ) ) {
570                         errors++;
571                         free( buf2 );
572                 }
573                 free( buf );
574
575                 buf = ensure_nlterm( strdup( "Stand up and cheer!" ) );                                 // force addition of newline
576                 if( buf ) {
577                         errors += fail_not_equal( strcmp( buf, "Stand up and cheer!\n" ), 0, "ensure nlterm didn't add newline" );
578                         free( buf );
579                         buf = NULL;
580                 }
581
582
583         // ------------- route manager request/response funcitons -------------------------------------------------------
584                 {
585                         rmr_mbuf_t*     smsg;
586
587                         smsg = rmr_alloc_msg( ctx, 1024 );
588                         send_rt_ack( ctx, smsg, "123456", 0, "no reason" );
589
590                         pctx = mk_dummy_ctx();
591                         ctx->rtg_whid = -1;
592                         state = send_update_req( pctx, ctx );
593                         errors += fail_not_equal( state, 0, "send_update_req did not return 0" );
594
595                         ctx->rtg_whid = rmr_wh_open( ctx, "localhost:19289" );
596                         state = send_update_req( pctx, ctx );
597                         errors += fail_if_equal( state, 0, "send_update_req to an open whid did not return 0" );
598                 }
599
600
601         // ------------- si only; fd to ep conversion functions ---------------------------------------------------------
602         #ifndef NNG_UNDER_TEST
603                 ep2 = (endpoint_t *) malloc( sizeof( *ep ) );
604
605                 fd2ep_init( ctx );
606                 fd2ep_add( ctx, 10, ep2 );
607
608                 ep = fd2ep_get( ctx, 10 );
609                 errors += fail_if_nil( ep, "fd2ep did not return pointer for known mapping" );
610                 errors += fail_if_false( ep == ep2,  "fd2ep did not return same pointer that was added" );
611
612                 ep = fd2ep_get( ctx, 20 );
613                 errors += fail_not_nil( ep, "fd2ep did returned a pointer for unknown mapping" );
614
615                 ep = fd2ep_del( ctx, 10 );
616                 errors += fail_if_nil( ep, "fd2ep delete did not return pointer for known mapping" );
617                 errors += fail_if_false( ep == ep2,  "fd2ep delete did not return same pointer that was added" );
618
619                 ep = fd2ep_del( ctx, 20 );
620                 errors += fail_not_nil( ep, "fd2ep delete returned a pointer for unknown mapping" );
621         #endif
622
623         return !!errors;                        // 1 or 0 regardless of count
624 }