e0dc4d8dec0cda2c777818bcc64df6a8442e8cc2
[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         snprintf( msg->xaction, 17, "%015d", 16 );              // dummy transaction id (emulation generates, this should arrive after a few calls to recv)
226
227         msg->state = 0;
228         msg = rmr_call( NULL, msg );
229         errors += fail_if( msg->state == 0, "rmr_call did not set message state when given message with nil context "  );
230
231         msg->mtype = 0;
232         msg = rmr_call( rmc, msg );                                             // this call should return a message as we can anticipate a dummy message in
233         errors += fail_if_nil( msg, "rmr_call returned a nil message on call expected to succeed "  );
234         if( msg ) {
235                 errors += fail_not_equal( msg->state, RMR_OK, "rmr_call did not properly set state on successful return "  );
236                 errors += fail_not_equal( errno, 0, "rmr_call did not properly set errno (a) on successful return "  );
237         }
238
239         snprintf( wbuf, 17, "%015d", 14 );                              // if we call receive we should find this in the first 15 tries
240         for( i = 0; i < 16; i++ ) {
241                 msg = rmr_rcv_msg( rmc, msg );
242                 if( msg ) {
243                         if( strcmp( wbuf, msg->xaction ) == 0 ) {               // found the queued message
244                                 break;
245                         }
246                         fprintf( stderr, "<INFO> msg: %s\n", msg->xaction );
247                 } else {
248                         errors += fail_if_nil( msg, "receive returnd nil msg while looking for queued message "  );
249                 }
250         }
251
252         errors += fail_if( i >= 16, "did not find expected message on queue "  );
253
254         if( ! msg ) {
255                 msg = rmr_alloc_msg( rmc, 2048 );                               // something buggered above; get a new one
256         }
257         msg = rmr_call( rmc, msg );                                                     // make a call that we never expect a response on
258         errors += fail_if_nil( msg, "rmr_call returned a non-nil message on call expected not to receive a response "  );
259         if( msg ) {
260                 errors += fail_if_equal( msg->state, RMR_OK, "rmr_call did not properly set state on queued message receive "  );
261                 errors += fail_if( errno == 0, "rmr_call did not properly set errno on queued message receivesuccessful "  );
262         }
263
264         msg = rmr_call( rmc, msg );                                             // this should "timeout" because the message xaction id won't ever appear again
265         errors += fail_if_nil( msg, "rmr_call returned a nil message on call expected to fail "  );
266         errors += fail_if( errno == 0, "rmr_call did not set errno on failure "  );
267
268         rmr_free_msg( NULL );                   // drive for coverage; nothing to check
269         rmr_free_msg( msg2 );
270
271
272         msg2 = rmr_torcv_msg( NULL, NULL, 10 );
273         errors += fail_not_nil( msg2, "rmr_torcv_msg returned a pointer when given nil information "  );
274         msg2 = rmr_torcv_msg( rmc, NULL, 10 );
275         errors += fail_if_nil( msg2, "rmr_torcv_msg did not return a message pointer when given a nil old msg "  );
276
277         // ---  test timeout receive; our dummy epoll function will return 1 ready on first call and 0 ready (timeout emulation) on second
278         //              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.
279         msg = NULL;
280         for( i = 0; i < 40; i++ ) {
281                 msg = rmr_torcv_msg( rmc, msg, 10 );
282                 errors += fail_if_nil( msg, "torcv_msg returned nil msg when message expected "  );
283                 if( msg ) {
284                         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
285                                 break;
286                         }
287                 }
288         }
289         errors += fail_if( i >= 40, "torcv_msg never returned a timeout "  );
290
291
292         // ---- trace things that are not a part of the mbuf_api functions and thus must be tested here
293         state = rmr_init_trace( NULL, 37 );                                             // coverage test nil context
294         errors += fail_not_equal( state, 0, "attempt to initialise trace with nil context returned non-zero state (a) "  );
295         errors += fail_if_equal( errno, 0, "attempt to initialise trace with nil context did not set errno as expected "  );
296
297         state = rmr_init_trace( rmc, 37 );
298         errors += fail_if_equal( state, 0, "attempt to set trace len in context was not successful "  );
299         errors += fail_not_equal( errno, 0, "attempt to set trace len in context did not clear errno "  );
300
301         msg = rmr_tralloc_msg( rmc, 1024, 17, "1904308620110417" );
302         errors += fail_if_nil( msg, "attempt to allocate message with trace data returned nil message "  );
303         state = rmr_get_trace( msg, wbuf, 17 );
304         errors += fail_not_equal( state, 17, "len of trace data (a) returned after msg allocation was not expected size (b) "  );
305         state = strcmp( wbuf, "1904308620110417" );
306         errors += fail_not_equal( state, 0, "trace data returned after tralloc was not correct "  );
307
308         em_send_failures = 1;
309         send_n_msgs( rmc, 30 );                 // send 30 messages with emulation failures
310         em_send_failures = 0;
311
312
313         rmr_close( NULL );                      // drive for coverage
314         rmr_close( rmc );                       // no return to check; drive for coverage
315
316
317         if( ! errors ) {
318                 fprintf( stderr, "<INFO> all RMr API tests pass\n" );
319         }
320         return !!errors;
321 }