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