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