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