fix(send): Add second key lookup if sub-id is set
[ric-plt/lib/rmr.git] / test / rmr_nng_api_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:       rmr_api_static_test.c
23         Abstract:       Specific tests related to the API functions in rmr_nng.c/rmr.c.
24                                 This should be included by a driver, but only the main RMr
25                                 driver and there will likely not be a specific stand alone driver
26                                 for just this small set of tests because of the depth of the
27                                 library needed to test at this level.
28
29                                 This can be used for both the nng and nanomsg outward facing
30                                 RMr API functions.
31
32                                 The message buffer specific API tests are in a different static
33                                 module.  API functions tested here are:
34                                          rmr_close
35                                          rmr_get_rcvfd
36                                          rmr_ready
37                                          rmr_init
38                                          rmr_set_rtimeout
39                                          rmr_set_stimeout
40                                          rmr_rcv_specific
41                                          rmr_torcv_msg
42                                          rmr_rcv_msg
43                                          rmr_call
44                                          rmr_rts_msg
45                                          rmr_send_msg
46                                          rmr_mtosend_msg
47                                          rmr_free_msg
48
49         Author:         E. Scott Daniels
50         Date:           5 April 2019
51 */
52
53 #include <unistd.h>
54 #include <stdio.h>
55 #include <stdlib.h>
56 #include <strings.h>
57 #include <errno.h>
58 #include <string.h>
59 #include <stdint.h>
60
61 #include "../src/common/include/rmr.h"
62 #include "../src/common/include/rmr_agnostic.h"
63
64 /*
65         Send a 'burst' of messages to drive some send retry failures to increase RMr coverage
66         by handling the retry caee.
67 */
68 static void send_n_msgs( void* ctx, int n ) {
69         rmr_mbuf_t*     msg;                    // message buffers
70         int i;
71
72         msg = rmr_alloc_msg( ctx,  1024 );
73         if( ! msg ) {
74                 return;
75         }
76
77         for( i = 0; i < n; i++ ) {
78                 //fprintf( stderr, "mass send\n" );
79                 msg->len = 100;
80                 msg->mtype = 1;
81                 msg->state = 999;
82                 errno = 999;
83                 msg = rmr_send_msg( ctx, msg );
84         }
85 }
86
87 static int rmr_api_test( ) {
88         int             errors = 0;
89         void*   rmc;                            // route manager context
90         void*   rmc2;                           // second context for non-listener init
91         rmr_mbuf_t*     msg;                    // message buffers
92         rmr_mbuf_t*     msg2;
93         int             v = 0;                                  // some value
94         char    wbuf[128];
95         int             i;
96         int             state;
97
98         v = rmr_ready( NULL );
99         errors += fail_if( v != 0, "rmr_ready returned true before initialisation "  );
100
101         if( (rmc = rmr_init( "4560", 1024, FL_NOTHREAD )) == NULL ) {
102                 fail_if_nil( rmc, "rmr_init returned a nil pointer "  );
103                 return 1;
104         }
105
106         if( (rmc2 = rmr_init( ":6789", 1024, FL_NOTHREAD )) == NULL ) {         // init without starting a thread
107                 errors += fail_if_nil( rmc, "rmr_init returned a nil pointer for non-threaded init "  );
108         }
109
110         free_ctx( rmc2 );                       // coverage
111
112         if( (rmc2 = rmr_init( NULL, 1024, FL_NOTHREAD )) == NULL ) {                    // drive default port selector code
113                 errors += fail_if_nil( rmc, "rmr_init returned a nil pointer when driving for default port "  );
114         }
115
116         v = rmr_ready( rmc );           // unknown return; not checking at the moment
117
118         msg = rmr_alloc_msg( NULL,  1024 );                                                                     // should return nil pointer
119         errors += fail_not_nil( msg, "rmr_alloc_msg didn't return nil when given nil context "  );
120
121         msg = rmr_alloc_msg( rmc, 2048 );                               // allocate larger than default size given on init
122         errors += fail_if_nil( msg, "rmr_alloc_msg returned nil msg pointer "  );
123
124         v = rmr_payload_size( NULL );
125         errors += fail_if( v >= 0, "rmr_payload_size returned valid size for nil message "  );
126         errors += fail_if( errno == 0, "rmr_payload_size did not set errno on failure "  );
127
128         v = rmr_payload_size( msg );
129         if( v >= 0 ) {
130                 errors += fail_not_equal( v, 2048, "rmr_payload_size returned invalid size (a) instead of expected size (b) "  );
131                 errors += fail_if( errno != 0, "rmr_payload_size did not clear errno on success "  );
132         } else {
133                 errors += fail_if( v < 0, "rmr_payload_size returned invalid size for good message "  );
134         }
135
136 #ifdef EMULATE_NNG
137         // this is only supported in nng, so behavour is different depending on the underlying library being tested
138         v = rmr_get_rcvfd( NULL );
139         errors += fail_if( v >= 0, "rmr_get_rcvfd returned a valid file descriptor when given nil context "  );
140         v = rmr_get_rcvfd( rmc );
141         errors += fail_if( v < 0, "rmr_get_rcvfd did not return a valid file descriptor "  );
142 #else
143         v = rmr_get_rcvfd( NULL );
144         errors += fail_if( v >= 0, "rmr_get_rcvfd returned a valid file descriptor when given nil context "  );
145         v = rmr_get_rcvfd( rmc );
146         errors += fail_if( v >= 0, "rmr_get_rcvfd returned a valid file descriptor (not supported in nanomsg)"  );
147 #endif
148
149         msg2 = rmr_send_msg( NULL, NULL );                      // drive for coverage
150         errors += fail_not_nil( msg2, "send_msg returned msg pointer when given a nil message and context "  );
151
152         msg->state = 0;
153         msg = rmr_send_msg( NULL, msg );
154         errors += fail_if( msg->state == 0, "rmr_send_msg did not set msg state when msg given with nil context "  );
155
156         // --- sends will fail with a no endpoint error until a dummy route table is set, so we test fail case first.
157         msg->len = 100;
158         msg->mtype = 1;
159         msg->state = 999;
160         errno = 999;
161         msg = rmr_send_msg( rmc, msg );
162         errors += fail_if_nil( msg, "send_msg_ did not return a message on send "  );
163         if( msg ) {
164                 errors += fail_not_equal( msg->state, RMR_ERR_NOENDPT, "send_msg did not return no endpoints before rtable added "  );
165                 errors += fail_if( errno == 0, "send_msg did not set errno "  );
166         }
167
168         gen_rt( rmc );          // --- after this point there is a dummy route table so send and rts calls should be ok
169
170         msg->len = 100;
171         msg->mtype = 1;
172         msg->state = 999;
173         errno = 999;
174         msg = rmr_send_msg( rmc, msg );
175         errors += fail_if_nil( msg, "send_msg_ did not return a message on send "  );
176         if( msg ) {
177                 errors += fail_not_equal( msg->state, RMR_OK, "send_msg returned bad status for send that should work "  );
178                 errors += fail_if( errno != 0, "send_msg set errno for send that should work "  );
179                 v = rmr_payload_size( msg );
180                 errors += fail_if( v != 2048, "send_msg did not allocate new buffer with correct size "  );
181         }
182
183         rmr_set_stimeout( NULL, 0 );
184         rmr_set_stimeout( rmc, 20 );
185         rmr_set_stimeout( rmc, -1 );
186         rmr_set_rtimeout( NULL, 0 );
187         rmr_set_rtimeout( rmc, 20 );
188         rmr_set_rtimeout( rmc, -1 );
189
190         msg2 = rmr_rcv_msg( NULL, NULL );
191         errors += fail_if( msg2 != NULL, "rmr_rcv_msg returned msg when given nil context and msg "  );
192
193         msg2 = rmr_rcv_msg( rmc, NULL );
194         errors += fail_if( msg2 == NULL, "rmr_rcv_msg returned nil msg when given nil msg "  );
195         if( msg2 ) {
196                 if( msg2->state != RMR_ERR_EMPTY ) {
197                         errors += fail_not_equal( msg2->state, RMR_OK, "receive given nil message did not return msg with good state (not empty) "  );
198                 }
199                 //errors += fail_not_equal( msg2->state, RMR_OK, "receive given nil message did not return msg with good state "  );
200         }
201
202
203         msg = rmr_rcv_msg( rmc, msg );
204         if( msg ) {
205                 errors += fail_not_equal( msg->state, RMR_OK, "rmr_rcv_msg did not return an ok state "  );
206                 errors += fail_not_equal( msg->len, 220, "rmr_rcv_msg returned message with invalid len "  );
207         } else {
208                 errors += fail_if_nil( msg, "rmr_rcv_msg returned a nil pointer "  );
209         }
210
211         rmr_rts_msg( NULL, NULL );                      // drive for coverage
212         rmr_rts_msg( rmc, NULL );
213         errors += fail_if( errno == 0, "rmr_rts_msg did not set errno when given a nil message "  );
214
215         msg->state = 0;
216         msg = rmr_rts_msg( NULL, msg );                 // should set state in msg
217         errors += fail_if_equal( msg->state, 0, "rmr_rts_msg did not set state when given valid message but no context "  );
218
219
220         msg = rmr_rts_msg( rmc, msg );                  // return the buffer to the sender
221         errors += fail_if_nil( msg, "rmr_rts_msg did not return a message pointer "  );
222         errors += fail_if( errno != 0, "rmr_rts_msg did not reset errno "  );
223
224
225
226         msg->state = 0;
227         msg = rmr_call( NULL, msg );
228         errors += fail_if( msg->state == 0, "rmr_call did not set message state when given message with nil context "  );
229
230         snprintf( msg->xaction, 17, "%015d", 16 );              // dummy transaction id (emulation generates, this should arrive after a few calls to recv)
231         msg->mtype = 0;
232         msg->sub_id = -1;
233         msg = rmr_call( rmc, msg );                                             // dummy nng/nano function will sequentually add xactions and should match or '16'
234         errors += fail_if_nil( msg, "rmr_call returned a nil message on call expected to succeed "  );
235         if( msg ) {
236                 errors += fail_not_equal( msg->state, RMR_OK, "rmr_call did not properly set state on successful return "  );
237                 errors += fail_not_equal( errno, 0, "rmr_call did not properly set errno (a) on successful return "  );
238         }
239
240         snprintf( wbuf, 17, "%015d", 14 );                              // while waiting, the queued messages should have #14, so issue a few receives looking for it
241         for( i = 0; i < 16; i++ ) {                                             // it should be in the first 15
242                 msg = rmr_rcv_msg( rmc, msg );
243                 if( msg ) {
244                         if( strcmp( wbuf, msg->xaction ) == 0 ) {               // found the queued message
245                                 break;
246                         }
247                         fprintf( stderr, "<INFO> msg: %s\n", msg->xaction );
248                 } else {
249                         errors += fail_if_nil( msg, "receive returnd nil msg while looking for queued message "  );
250                 }
251         }
252
253         errors += fail_if( i >= 16, "did not find expected message on queue "  );
254
255         if( ! msg ) {
256                 msg = rmr_alloc_msg( rmc, 2048 );                               // something buggered above; get a new one
257         }
258         msg->mtype = 0;
259         msg->sub_id = -1;
260         msg = rmr_call( rmc, msg );                                                     // make a call that we never expect a response on (nil pointer back)
261         errors += fail_not_nil( msg, "rmr_call returned a nil message on call expected not to receive a response "  );
262         errors += fail_if( errno == 0, "rmr_call did not set errno on failure "  );
263
264         rmr_free_msg( NULL );                   // drive for coverage; nothing to check
265         rmr_free_msg( msg2 );
266
267
268         msg2 = rmr_torcv_msg( NULL, NULL, 10 );
269         errors += fail_not_nil( msg2, "rmr_torcv_msg returned a pointer when given nil information "  );
270         msg2 = rmr_torcv_msg( rmc, NULL, 10 );
271         errors += fail_if_nil( msg2, "rmr_torcv_msg did not return a message pointer when given a nil old msg "  );
272
273         // ---  test timeout receive; our dummy epoll function will return 1 ready on first call and 0 ready (timeout emulation) on second
274         //              however we must drain the swamp (queue) first, so run until we get a timeout error, or 20 and report error if we get to 20.
275         msg = NULL;
276         for( i = 0; i < 40; i++ ) {
277                 msg = rmr_torcv_msg( rmc, msg, 10 );
278                 errors += fail_if_nil( msg, "torcv_msg returned nil msg when message expected "  );
279                 if( msg ) {
280                         if( msg->state == RMR_ERR_TIMEOUT || msg->state == RMR_ERR_EMPTY ) {            // queue drained and we've seen both states from poll if we get a timeout
281                                 break;
282                         }
283                 }
284         }
285         errors += fail_if( i >= 40, "torcv_msg never returned a timeout "  );
286
287
288         // ---- trace things that are not a part of the mbuf_api functions and thus must be tested here
289         state = rmr_init_trace( NULL, 37 );                                             // coverage test nil context
290         errors += fail_not_equal( state, 0, "attempt to initialise trace with nil context returned non-zero state (a) "  );
291         errors += fail_if_equal( errno, 0, "attempt to initialise trace with nil context did not set errno as expected "  );
292
293         state = rmr_init_trace( rmc, 37 );
294         errors += fail_if_equal( state, 0, "attempt to set trace len in context was not successful "  );
295         errors += fail_not_equal( errno, 0, "attempt to set trace len in context did not clear errno "  );
296
297         msg = rmr_tralloc_msg( rmc, 1024, 17, "1904308620110417" );
298         errors += fail_if_nil( msg, "attempt to allocate message with trace data returned nil message "  );
299         state = rmr_get_trace( msg, wbuf, 17 );
300         errors += fail_not_equal( state, 17, "len of trace data (a) returned after msg allocation was not expected size (b) "  );
301         state = strcmp( wbuf, "1904308620110417" );
302         errors += fail_not_equal( state, 0, "trace data returned after tralloc was not correct "  );
303
304         em_send_failures = 1;
305         send_n_msgs( rmc, 30 );                 // send 30 messages with emulation failures
306         em_send_failures = 0;
307
308
309         rmr_close( NULL );                      // drive for coverage
310         rmr_close( rmc );                       // no return to check; drive for coverage
311
312
313         if( ! errors ) {
314                 fprintf( stderr, "<INFO> all RMr API tests pass\n" );
315         }
316         return !!errors;
317 }