1 // : vi ts=4 sw=4 noet :
3 ==================================================================================
4 Copyright (c) 2019 Nokia
5 Copyright (c) 2018-2019 AT&T Intellectual Property.
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
11 http://www.apache.org/licenses/LICENSE-2.0
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 ==================================================================================
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.
26 Author: E. Scott Daniels
38 #include <semaphore.h>
41 #include "rmr_agnostic.h"
43 typedef struct entry_info {
50 Driven by symtab foreach element of one space.
51 We count using the data as a counter.
53 static void count_things( void* st, void* entry, char const* name, void* thing, void* vdata ) {
57 if( (counter = (int *) vdata) != NULL ) {
64 Returns the number of entries in the table for the given class.
66 static int count_entries( route_table_t* rt, int class ) {
76 rmr_sym_foreach_class( rt->hash, class, count_things, &counter ); // run each and update counter
82 Builds a route table key.
84 static uint64_t build_key( uint32_t mtype, uint32_t sid ) {
87 k = (uint64_t) sid << 32;
90 fprintf( stderr, "<INFO> build key: %x %x --> %llx\n", (int) mtype, (int) sid, (long long) k );
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
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
106 endpoint_t* ep; // endpoint added
108 int more = 0; // more flag from round robin
109 int errors = 0; // number errors found
112 int c1; // general counters
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
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
131 #ifndef NNG_UNDER_TEST
132 si_ctx_t* si_ctx = NULL;
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 );
138 write( i, "2\n", 2 );
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.)
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
155 gcounts[0] = 1; // first entry has 1 group with 2 endpoints; message type 0, sid 0
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
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++;
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++;
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++;
180 gcounts[4] = 1; // three entries for mt==3 with different sids
182 mtypes[4] = build_key( 3, 0 );
183 entries[enu].group = 0; entries[enu].ep_name = "localhost:5500"; enu++;
187 mtypes[5] = build_key( 3, 11 );
188 entries[enu].group = 0; entries[enu].ep_name = "localhost:5511"; enu++;
192 mtypes[6] = build_key( 3, -1 );
193 entries[enu].group = 0; entries[enu].ep_name = "localhost:5512"; enu++;
196 rt = uta_rt_init( NULL );
197 errors += fail_if_false( rt == NULL, "rt_init given a nil context didn't return nil" );
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" );
208 for( i = 0; i < sizeof( gcounts )/sizeof( int ); i++ ) { // add entries defined above
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" );
217 fprintf( stderr, "<SNAFU> internal testing error -- rte was nil for gcount == 0\n" );
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" );
229 // ----- end hacking together a route table ---------------------------------------------------
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" );
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)" );
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" );
242 errors += fail_if_false( crt->ephash == rt->ephash, "ephash pointer in cloned table is not right" );
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" );
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)" );
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)" );
259 errors += fail_if_false( crt->ephash == rt->ephash, "ephash pointer in cloned table (all) is not right" );
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 ) );
268 fprintf( stderr, "<FAIL> cannot acllocate a context, cannot continue rtable tests\n" );
272 ctx = mk_dummy_ctx();
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)" );
283 #ifdef NNG_UNDER_TEST
284 state = uta_epsock_byname( rt, "localhost:4561", &nn_sock, &ep ); // this should be found
286 state = uta_epsock_byname( ctx, "localhost:4561", &nn_sock, &ep ); // this should be found
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" );
294 state = uta_epsock_byname( NULL, "localhost:4561", &nn_sock, &ep ); // test coverage on nil checks
296 state = uta_epsock_byname( NULL, "localhost:4561", &nn_sock, &ep );
298 errors += fail_not_equal( state, 0, "socket (by name) nil check returned true" );
300 if( ep ) { // if previous test fails, cant run this
303 state = uta_epsock_byname( rt, "localhost:4561", &nn_sock, NULL ); // test coverage on nil checks
305 state = uta_epsock_byname( ctx, "localhost:4561", &nn_sock, NULL );
307 errors += fail_if_equal( state, 0, "socket (by name) open ep check returned false" );
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" );
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" );
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" );
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" );
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" );
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" );
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" );
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" );
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" );
343 rte = uta_get_rte( rt, 0, 1, FALSE ); // get an rte for the next loop
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
349 value = uta_epsock_rr( ctx, rte, 0, &more, &nn_sock, &ep );
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" );
359 rte = uta_get_rte( rt, 0, 3, FALSE ); // get an rte for the next loop
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
365 value = uta_epsock_rr( ctx, rte, 0, NULL, &nn_sock, &ep );
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" );
376 rte = uta_get_rte( rt, 11, 3, TRUE );
377 #ifdef NNG_UNDER_TEST
378 state = uta_epsock_rr( rte, 22, NULL, NULL, &ep );
380 state = uta_epsock_rr( ctx, rte, 22, NULL, NULL, &ep );
382 errors += fail_if_true( state, "uta_epsock_rr returned bad (non-zero) state when given nil socket pointer" );
385 uta_rt_clone( ctx, NULL, NULL, 0 ); // verify null parms don't crash things
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 );
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" );
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" );
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" );
400 uta_add_rte( NULL, 99, 1 );
401 uta_get_rte( NULL, 0, 1000, TRUE );
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 );
407 buf = uta_fib( ".gitignore" );
408 errors += fail_if_nil( buf, "buffer from read file into buffer" );
412 buf = uta_fib( "no-file" );
413 errors += fail_if_nil( buf, "buffer from read file into buffer (no file)" );
418 fprintf( stderr, "<INFO> test is overtly dropping rt table at %p\n", rt );
424 // --- force the load of a RT which has some edge case forcing issues
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"
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"
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"
450 "# for an update to the existing table\n"
452 "# not in progress; drive that exception check\n"
453 "update | end | 23\n"
455 "update | start | dummy-seed\n"
456 "mse | 2 | 2 | localhost:2222\n"
457 "# no table end for exception handling\n"
459 "update | start | dummy-seed\n"
460 "mse | 2 | 2 | localhost:2222\n"
461 "update | end | 1\n";
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" );
468 unsetenv( "RMR_SEED_RT" ); // remove for next read try
469 read_static_rt( ctx, 0 ); // drive for not there coverage
473 buf = uta_fib( "no-suhch-file" ); // drive some error checking for coverage
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" );
485 #ifdef NNG_UNDER_TEST
486 state = uta_link2( ep );
488 state = uta_link2( ctx, ep );
490 errors += fail_if_true( state, "link2 did not return false when given a bad target name" );
492 #ifdef NNG_UNDER_TEST
493 state = uta_link2( NULL );
495 state = uta_link2( ctx, NULL );
496 errors += fail_if_true( state, "link2 did not return false when given nil ep pointer" );
498 state = uta_link2( NULL, ep );
500 errors += fail_if_true( state, "link2 did not return false when given nil pointer" );
502 ep->name = strdup( "localhost:5512" );
504 #ifdef NNG_UNDER_TEST
505 state = uta_link2( ep ); // drive for coverage
507 state = uta_link2( ctx, ep );
509 errors += fail_if_false( state, "link2 did returned false when given open ep" );
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
514 state = rt_link2_ep( NULL, ep );
515 errors += fail_if_true( state, "rt_link2_ep returned true when given bad context" );
517 state = rt_link2_ep( ctx, NULL );
518 errors += fail_if_true( state, "rt_link2_ep returned true when given bad ep" );
521 state = rt_link2_ep( ctx, ep );
522 errors += fail_if_false( state, "rt_link2_ep returned false when given an open ep" );
525 state = rt_link2_ep( ctx, ep );
526 errors += fail_if_false( state, "rt_link2_ep returned false when given a closed ep" );
530 errors += fail_if_true( ep->open, "uta_ep_failed didn't set open flag to false" );
535 // ----------------- test the meid support for looking up an endpoint based on the meid in the message -----
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
542 mbuf = rmr_alloc_msg( ctx, 2048 ); // buffer to play with
544 rmr_str2meid( mbuf, "meid1" ); // id that we know is in the map
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" );
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" );
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" );
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" );
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" );
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" );
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" );
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" );
583 buf = ensure_nlterm( NULL );
584 errors += fail_if_nil( buf, "ensure nlterm returned null pointer when given nil ptr" );
586 errors += fail_not_equal( strlen( buf ), 1, "ensure nlterm returned incorrect length string when given nil pointer" );
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" );
593 errors += fail_not_equal( strlen( buf ), 2, "ensure nlterm returned incorrect length string when given single char string" );
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" ) ) {
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" ) ) {
613 buf = ensure_nlterm( strdup( "Stand up and cheer!" ) ); // force addition of newline
615 errors += fail_not_equal( strcmp( buf, "Stand up and cheer!\n" ), 0, "ensure nlterm didn't add newline" );
621 // ------------- route manager request/response funcitons -------------------------------------------------------
625 smsg = rmr_alloc_msg( ctx, 1024 );
626 send_rt_ack( ctx, smsg, "123456", 0, "no reason" );
628 pctx = mk_dummy_ctx();
630 state = send_update_req( pctx, ctx );
631 errors += fail_not_equal( state, 0, "send_update_req did not return 0" );
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" );
639 // ------------- si only; fd to ep conversion functions ---------------------------------------------------------
640 #ifndef NNG_UNDER_TEST
641 ep2 = (endpoint_t *) malloc( sizeof( *ep ) );
644 fd2ep_add( ctx, 10, ep2 );
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" );
650 ep = fd2ep_get( ctx, 20 );
651 errors += fail_not_nil( ep, "fd2ep did returned a pointer for unknown mapping" );
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" );
657 ep = fd2ep_del( ctx, 20 );
658 errors += fail_not_nil( ep, "fd2ep delete returned a pointer for unknown mapping" );
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 );
666 return !!errors; // 1 or 0 regardless of count