b0612d8160f79b6ed626af7b6ff2aece42cd830c
[ric-plt/xapp-frame-cpp.git] / test / unit_test.cpp
1 // vim: ts=4 sw=4 noet :
2 /*
3 ==================================================================================
4        Copyright (c) 2020 Nokia
5        Copyright (c) 2020 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         Mnemonic:       Unit_test.cpp
23         Abstract:       This is the unit test driver for the C++ xAPP framework. It 
24                                 operates by including all of the modules directly (in order
25                                 to build them with the necessary coverage flags), then 
26                                 drives all that it can.  The RMR emulation module provides
27                                 emulated RMR functions which simulate the creation, sending
28                                 and receiving of messages etc.
29
30         Date:           20 March 2020
31         Author:         E. Scott Daniels
32 */
33
34 #include <memory>
35
36
37 #include "../src/messaging/callback.hpp"
38 #include "../src/messaging/default_cb.hpp"
39 #include "../src/messaging/message.hpp"
40 #include "../src/messaging/messenger.hpp"
41 #include "../src/messaging/msg_component.hpp"
42 #include "../src/xapp/xapp.hpp"
43
44 #include "../src/messaging/callback.cpp"
45 #include "../src/messaging/default_cb.cpp"
46 #include "../src/messaging/message.cpp"
47 #include "../src/messaging/messenger.cpp"
48 #include "../src/xapp/xapp.cpp"
49
50 /*
51         callback error counts are global for ease. They track the number of times each callback
52         was invoked with the expected message type(s) and any times they were not.
53 */
54 int err_cb1 = 0;
55 int err_cb2 = 0;
56 int err_cbd = 0;
57
58 int good_cb1 = 0;
59 int good_cb2 = 0;
60 int good_cbd = 0;
61
62 /*
63         callback functions to register; driven as we "receive" messages (the RMR emulation package 
64         will generate a message every time the receive function is called).
65 */
66 void cb1( Message& mbuf, int mtype, int subid, int len, Msg_component payload,  void* data ) {
67         if( mtype != 1 ) {      // should only be driven for type 1 messages
68                 err_cb1++;
69         } else {
70                 good_cb1++;
71         }
72 }
73 void cb2( Message& mbuf, int mtype, int subid, int len, Msg_component payload,  void* data ) {
74         if( mtype != 2 ) {      // should only be driven for type 2 messages
75                 err_cb2++;
76         } else {
77                 good_cb2++;
78         }
79 }
80 void cbd( Message& mbuf, int mtype, int subid, int len, Msg_component payload,  void* data ) {
81         if( mtype > 0 && mtype < 3 ) {                          // should only be driven for types that arent 1 or 2 
82                 if( err_cbd < 10 ) {
83                         fprintf( stderr, "<FAIL> cbd: bad message type: %d\n", mtype );
84                 }
85                 err_cbd++;
86         } else {
87                 good_cbd++;
88         }
89 }
90
91 /*
92         The Xapp Run() function only returns when Xapp is asked to stop, and that
93         isn't supported from inside any of the callbacks.  This funciton is 
94         started in a thread and after a few seconds it will drive the halt 
95         function in the Xapp instance to stop the run function and allow the
96         unit test to finish.
97 */
98 void killer( std::shared_ptr<Xapp> x ) {
99         fprintf( stderr, "<INFO> killer is waiting in the shadows\n" );
100         sleep( 2 );
101         fprintf( stderr, "<INFO> killer is on the loose\n" );
102         x->Halt();
103 }
104
105 int main( int argc, char** argv ) {
106         std::thread* tinfo;                                     // we'll start a thread that will shut things down after a few seconds
107         std::unique_ptr<Message> msg;
108         std::shared_ptr<Xapp> x;
109         Msg_component payload;
110         std::unique_ptr<unsigned char> ucs;
111         unsigned char* new_payload;
112         std::shared_ptr<unsigned char> new_p_ref;       // reference to payload to pass to send functions
113         char*   port = (char *) "4560";
114         int             ai = 1;                                                 // arg processing index
115         int             nthreads = 2;                                   // ensure the for loop is executed in setup
116         int             i;
117         int             len;
118         int             errors = 0;
119         char    wbuf[256];
120
121         ai = 1;
122         while( ai < argc ) {                            // very simple flag processing (no bounds/error checking)
123                 if( argv[ai][0] != '-' )  {
124                         break;
125                 }
126
127                 switch( argv[ai][1] ) {                 // we only support -x so -xy must be -x -y
128                         case 'p': 
129                                 port = argv[ai+1];      
130                                 ai++;
131                                 break;
132
133                         case 't':
134                                 nthreads = atoi( argv[ai+1] );
135                                 ai++;
136                                 break;
137                 }
138
139                 ai++;
140         }
141         
142         x = std::shared_ptr<Xapp>( new Xapp( port, true ) );
143         x->Add_msg_cb( 1, cb1, NULL );
144         x->Add_msg_cb( 2, cb2, NULL );
145         x->Add_msg_cb( -1, cbd, NULL );
146
147         msg = x->Alloc_msg( 2048 );
148         payload = msg->Get_payload();
149         msg->Set_len( 128 );
150         msg->Set_mtype( 100 );
151         msg->Set_subid( -10 );
152
153         ucs = msg->Copy_payload( );
154         if( ucs == NULL ) {
155                 fprintf( stderr, "<FAIL> expected pointer to copy payload but got nil\n" );
156                 errors++;
157         }
158
159         ucs = msg->Get_meid();
160         if( ucs == NULL ) {
161                 fprintf( stderr, "<FAIL> expected pointer to meid copy but got nil\n" );
162                 errors++;
163         }
164
165         ucs = msg->Get_src();
166         if( ucs == NULL ) {
167                 fprintf( stderr, "<FAIL> expected pointer to src copy but got nil\n" );
168                 errors++;
169         }
170
171         i = msg->Get_available_size();
172         if( i != 2048 ) {
173                 fprintf( stderr, "<FAIL> len expected payload avail size of 2048 but got %d\n", i );
174                 errors++;
175         }
176
177         i = msg->Get_mtype();
178         if( i != 100 ) {
179                 fprintf( stderr, "<FAIL> expected mtype of 100 but got %d\n", i );
180                 errors++;
181         }
182
183         i = msg->Get_state( );
184         if( i != 0 ) {
185                 fprintf( stderr, "<FAIL> expected state of 0 but got %d\n", i );
186                 errors++;
187         }
188
189         i = msg->Get_subid();
190         if( i != -10 ) {
191                 fprintf( stderr, "<FAIL> expected subid of -10 but got %d\n", i );
192                 errors++;
193         }
194
195         i = msg->Get_len();
196         if( i != 128 ) {
197                 fprintf( stderr, "<FAIL> len expected 128 but got %d\n", i );
198                 errors++;
199         }
200
201         msg->Send();                            // generic send as is functions
202         msg->Reply();
203
204         new_payload = (unsigned char *) malloc( sizeof( unsigned char ) * 2048 );       // a large payload
205         memset( new_payload, 0 , sizeof( unsigned char ) * 2048 );
206         new_p_ref = std::shared_ptr<unsigned char>( new_payload );                                      // reference it for send calls
207
208         msg->Set_meid( new_p_ref );
209
210         msg->Send_msg( 255, new_p_ref );                                                                                        // send without changing the message type/subid from above
211         msg->Send_msg( 255, new_payload );                                                                                      // drive the alternate prototype
212         msg->Send_msg( 100, 1, 128, new_p_ref );                                                                        // send using just 128 bytes of payload
213         msg->Send_msg( 100, 1, 128, new_payload );                                                                      // drive with alternate prototype
214
215         msg->Set_len( 128 );
216         msg->Set_mtype( 100 );
217         msg->Set_subid( -10 );
218
219         msg->Send_response( 100, new_p_ref );                                                                           // send a response (rts) with establisehd message type etc
220         msg->Send_response( 100, new_payload );
221         msg->Send_response( 100, 10, 100, new_p_ref );
222         msg->Send_response( 100, 10, 100, new_payload );
223
224
225         msg = NULL;                                                             // should drive the message destroyer for coverage
226
227         msg = x->Receive( 2000 );
228         if( msg == NULL ) {
229                 fprintf( stderr, "<FAIL> expected message from receive but got nil\n" );
230                 errors++;
231         }
232
233         tinfo = new std::thread;                                // start killer thread to terminate things so that run doesn't hang forever
234         tinfo = new std::thread( killer, x );
235
236         x->Run( nthreads );
237         x->Halt();                      // drive for coverage
238
239         if( err_cb1 + err_cb2 + err_cbd > 0 ) {
240                 fprintf( stderr, "<FAIL> one or more callbacks reported an error:  [%d] [%d] [%d]\n", err_cb1, err_cb2, err_cbd );
241                 fprintf( stderr, "<INFO> callback good values:  [%d] [%d] [%d]\n", good_cb1, good_cb2, good_cbd );
242                 errors++;
243         }
244
245         // -----  specific move/copy coverage drivers ---------------------------
246         
247         Messenger m1( (char *) "1234", false );         // messenger class does NOT permit copies, so no need to test
248         Messenger m2( (char *) "9999", false );
249         m1 = std::move( m2 );                                           // drives move operator= function
250         Messenger m3 = std::move( m1 );                         // drives move constructor function
251
252         std::unique_ptr<Message> msg2 = x->Alloc_msg( 2048 );
253         std::unique_ptr<Message> msg3 = x->Alloc_msg( 4096 );
254
255         snprintf( wbuf, sizeof( wbuf ), "Stand up and cheer!!" );
256         msg3->Set_len( strlen( wbuf ) );
257         strcpy( (char *) (msg3->Get_payload()).get(), wbuf );                   // populate the payload to vet copy later
258         fprintf( stderr, "<DBUG> set string (%s) \n", (char *) (msg3->Get_payload()).get() );
259
260         Message msg4 = *(msg3.get());                                                                   // drive copy builder; msg4 should have a 4096 byte payload
261         fprintf( stderr, "<DBUG> copy string (%s) \n", (char *) (msg4.Get_payload()).get() );   // and payload should be coppied
262         if( msg4.Get_available_size() != 4096 ) {
263                 errors++;
264                 fprintf( stderr, "<FAIL> message copy builder payload size smells: expected 4096, got %d\n", msg4.Get_available_size() );
265         }
266         if( strcmp( (char *) msg4.Get_payload().get(), wbuf ) != 0 ) {
267                 errors++;
268                 fprintf( stderr, "<FAIL> message copy builder payload of copy not the expected string\n" );
269         }
270
271         snprintf( wbuf, sizeof( wbuf ), "Rambling Wreck; GT!" );                // different string into msg 2 to ensure copy replaced msg3 string
272         strcpy( (char *) (msg2->Get_payload()).get(), wbuf );                   // populate the msg2 payload to vet copy
273         msg2->Set_len( strlen( wbuf ) );
274         *msg3 = *msg2;                                                                                                  // drive the copy operator= function
275         if( msg3->Get_available_size() != 2048 ) {
276                 errors++;
277                 fprintf( stderr, "<FAIL> message copy operator payload size smells: expected 2048, got %d\n", msg3->Get_available_size() );
278         }
279         if( strcmp( (char *) msg3->Get_payload().get(), wbuf ) != 0 ) {
280                 errors++;
281                 fprintf( stderr, "<FAIL> message copy builder payload of copy not the expected string\n" );
282         }
283
284         Message msg5 = std::move( *(msg3.get()) );                                      // drive move constructor
285         if( msg5.Get_available_size() != 2048 ) {
286                 errors++;
287                 fprintf( stderr, "<FAIL> message copy operator payload size smells: expected 2048, got %d\n", msg5.Get_available_size() );
288         }
289         if( strcmp( (char *) msg5.Get_payload().get(), wbuf ) != 0 ) {
290                 errors++;
291                 fprintf( stderr, "<FAIL> message copy builder payload of copy not the expected string\n" );
292         }
293
294         msg5.Set_len( 2 );                                      // bogus len for vetting later
295         msg5 = std::move( *(msg3.get()) );
296         if( msg5.Get_len() == 21 ) {
297                 errors++;
298                 fprintf( stderr, "<FAIL> message move operator payload len smells: expected 21, got %d\n", msg5.Get_len() );
299         }
300
301         return errors > 0;
302 }