Add metrics to the framework
[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/alarm/alarm.hpp"
43 #include "../src/metrics/metrics.hpp"
44 #include "../src/xapp/xapp.hpp"
45
46 #include "../src/messaging/callback.cpp"
47 #include "../src/messaging/default_cb.cpp"
48 #include "../src/messaging/message.cpp"
49 #include "../src/messaging/messenger.cpp"
50 #include "../src/alarm/alarm.cpp"
51 #include "../src/xapp/xapp.cpp"
52
53 #include "ut_support.cpp"
54
55 // ---------------------------------------------------------------------------------------------
56 /*
57         callback error counts are global for ease. They track the number of times each callback
58         was invoked with the expected message type(s) and any times they were not.
59 */
60 int err_cb1 = 0;
61 int err_cb2 = 0;
62 int err_cbd = 0;
63
64 int good_cb1 = 0;
65 int good_cb2 = 0;
66 int good_cbd = 0;
67
68 /*
69         callback functions to register; driven as we "receive" messages (the RMR emulation package
70         will generate a message every time the receive function is called).
71 */
72 void cb1( xapp::Message& mbuf, int mtype, int subid, int len, xapp::Msg_component payload,  void* data ) {
73         if( mtype != 1 ) {      // should only be driven for type 1 messages
74                 err_cb1++;
75         } else {
76                 good_cb1++;
77         }
78 }
79 void cb2( xapp::Message& mbuf, int mtype, int subid, int len, xapp::Msg_component payload,  void* data ) {
80         if( mtype != 2 ) {      // should only be driven for type 2 messages
81                 err_cb2++;
82         } else {
83                 good_cb2++;
84         }
85 }
86 void cbd( xapp::Message& mbuf, int mtype, int subid, int len, xapp::Msg_component payload,  void* data ) {
87         if( mtype > 0 && mtype < 3 ) {                          // should only be driven for types that arent 1 or 2
88                 if( err_cbd < 10 ) {
89                         fprintf( stderr, "<FAIL> cbd: bad message type: %d\n", mtype );
90                 }
91                 err_cbd++;
92         } else {
93                 good_cbd++;
94         }
95 }
96
97 /*
98         The Xapp Run() function only returns when Xapp is asked to stop, and that
99         isn't supported from inside any of the callbacks.  This funciton is
100         started in a thread and after a few seconds it will drive the halt
101         function in the Xapp instance to stop the run function and allow the
102         unit test to finish.
103 */
104 void killer( std::shared_ptr<Xapp> x ) {
105         fprintf( stderr, "<INFO> killer is waiting in the shadows\n" );
106         sleep( 2 );
107         fprintf( stderr, "<INFO> killer is on the loose\n" );
108         x->Halt();
109 }
110
111 /*
112         Drive the constructors so that we actually see the coverage
113         in the .gc* files.  The metrics tests will actually verify that
114         the various underlying functions work.
115 */
116 static int metrics( std::shared_ptr<Xapp> x ) {
117         std::shared_ptr<xapp::Metrics> m;
118
119         m = x->Alloc_metrics( );                                                // basic construction
120         m = x->Alloc_metrics( "different-source" );              // drive alternate builders
121         m = x->Alloc_metrics( "different-app", "different-source" );
122 }
123
124 int main( int argc, char** argv ) {
125         std::thread* tinfo;                                     // we'll start a thread that will shut things down after a few seconds
126         std::unique_ptr<xapp::Message> msg;
127         std::shared_ptr<Xapp> x;
128         xapp::Msg_component payload;
129         std::unique_ptr<unsigned char> ucs;
130         unsigned char* new_payload;
131         std::shared_ptr<unsigned char> new_p_ref;       // reference to payload to pass to send functions
132         char*   port = (char *) "4560";
133         int             ai = 1;                                                 // arg processing index
134         int             nthreads = 2;                                   // ensure the for loop is executed in setup
135         int             i;
136         int             len;
137         int             errors = 0;
138         char    wbuf[256];
139
140         ai = 1;
141         while( ai < argc ) {                            // very simple flag processing (no bounds/error checking)
142                 if( argv[ai][0] != '-' )  {
143                         break;
144                 }
145
146                 switch( argv[ai][1] ) {                 // we only support -x so -xy must be -x -y
147                         case 'p':
148                                 port = argv[ai+1];
149                                 ai++;
150                                 break;
151
152                         case 't':
153                                 nthreads = atoi( argv[ai+1] );
154                                 ai++;
155                                 break;
156                 }
157
158                 ai++;
159         }
160
161         set_test_name( "unit_test" );
162
163         // ------------------- generic xapp tests ----------------------------------------------
164         x = std::shared_ptr<Xapp>( new Xapp( port, true ) );
165         x->Add_msg_cb( 1, cb1, NULL );
166         x->Add_msg_cb( 2, cb2, NULL );
167         x->Add_msg_cb( -1, cbd, NULL );
168
169         msg = x->Alloc_msg( 2048 );
170         payload = msg->Get_payload();
171         msg->Set_len( 128 );
172         msg->Set_mtype( 100 );
173         msg->Set_subid( -10 );
174
175         ucs = msg->Copy_payload( );
176         if( ucs == NULL ) {
177                 fprintf( stderr, "<FAIL> expected pointer to copy payload but got nil\n" );
178                 errors++;
179         }
180
181         ucs = msg->Get_meid();
182         if( ucs == NULL ) {
183                 fprintf( stderr, "<FAIL> expected pointer to meid copy but got nil\n" );
184                 errors++;
185         }
186
187         ucs = msg->Get_src();
188         if( ucs == NULL ) {
189                 fprintf( stderr, "<FAIL> expected pointer to src copy but got nil\n" );
190                 errors++;
191         }
192
193         i = msg->Get_available_size();
194         if( i != 2048 ) {
195                 fprintf( stderr, "<FAIL> len expected payload avail size of 2048 but got %d\n", i );
196                 errors++;
197         }
198
199         i = msg->Get_mtype();
200         if( i != 100 ) {
201                 fprintf( stderr, "<FAIL> expected mtype of 100 but got %d\n", i );
202                 errors++;
203         }
204
205         i = msg->Get_state( );
206         if( i != 0 ) {
207                 fprintf( stderr, "<FAIL> expected state of 0 but got %d\n", i );
208                 errors++;
209         }
210
211         i = msg->Get_subid();
212         if( i != -10 ) {
213                 fprintf( stderr, "<FAIL> expected subid of -10 but got %d\n", i );
214                 errors++;
215         }
216
217         i = msg->Get_len();
218         if( i != 128 ) {
219                 fprintf( stderr, "<FAIL> len expected 128 but got %d\n", i );
220                 errors++;
221         }
222
223         msg->Send();                            // generic send as is functions
224         msg->Reply();
225
226         new_payload = (unsigned char *) malloc( sizeof( unsigned char ) * 2048 );       // a large payload
227         memset( new_payload, 0 , sizeof( unsigned char ) * 2048 );
228         new_p_ref = std::shared_ptr<unsigned char>( new_payload );                                      // reference it for send calls
229
230         msg->Set_meid( new_p_ref );
231
232         msg->Send_msg( 255, new_p_ref );                                                                                        // send without changing the message type/subid from above
233         msg->Send_msg( 255, new_payload );                                                                                      // drive the alternate prototype
234         msg->Send_msg( 100, 1, 128, new_p_ref );                                                                        // send using just 128 bytes of payload
235         msg->Send_msg( 100, 1, 128, new_payload );                                                                      // drive with alternate prototype
236
237         msg->Set_len( 128 );
238         msg->Set_mtype( 100 );
239         msg->Set_subid( -10 );
240
241         msg->Send_response( 100, new_p_ref );                                                                           // send a response (rts) with establisehd message type etc
242         msg->Send_response( 100, new_payload );
243         msg->Send_response( 100, 10, 100, new_p_ref );
244         msg->Send_response( 100, 10, 100, new_payload );
245
246
247         msg = NULL;                                                             // should drive the message destroyer for coverage
248
249         msg = x->Receive( 2000 );
250         if( msg == NULL ) {
251                 fprintf( stderr, "<FAIL> expected message from receive but got nil\n" );
252                 errors++;
253         }
254
255         tinfo = new std::thread;                                // start killer thread to terminate things so that run doesn't hang forever
256         tinfo = new std::thread( killer, x );
257
258         x->Run( nthreads );
259         x->Halt();                      // drive for coverage
260
261         if( err_cb1 + err_cb2 + err_cbd > 0 ) {
262                 fprintf( stderr, "<FAIL> one or more callbacks reported an error:  [%d] [%d] [%d]\n", err_cb1, err_cb2, err_cbd );
263                 fprintf( stderr, "<INFO> callback good values:  [%d] [%d] [%d]\n", good_cb1, good_cb2, good_cbd );
264                 errors++;
265         }
266
267         // -----  specific move/copy coverage drivers ---------------------------
268
269         xapp::Messenger m1( (char *) "1234", false );           // messenger class does NOT permit copies, so no need to test
270         xapp::Messenger m2( (char *) "9999", false );
271         m1 = std::move( m2 );                                           // drives move operator= function
272         xapp::Messenger m3 = std::move( m1 );                           // drives move constructor function
273
274         std::unique_ptr<xapp::Message> msg2 = x->Alloc_msg( 2048 );
275         std::unique_ptr<xapp::Message> msg3 = x->Alloc_msg( 4096 );
276
277         snprintf( wbuf, sizeof( wbuf ), "Stand up and cheer!!" );
278         msg3->Set_len( strlen( wbuf ) );
279         strcpy( (char *) (msg3->Get_payload()).get(), wbuf );                   // populate the payload to vet copy later
280         fprintf( stderr, "<DBUG> set string (%s) \n", (char *) (msg3->Get_payload()).get() );
281
282         xapp::Message msg4 = *(msg3.get());                                                                     // drive copy builder; msg4 should have a 4096 byte payload
283         fprintf( stderr, "<DBUG> copy string (%s) \n", (char *) (msg4.Get_payload()).get() );   // and payload should be coppied
284         if( msg4.Get_available_size() != 4096 ) {
285                 errors++;
286                 fprintf( stderr, "<FAIL> message copy builder payload size smells: expected 4096, got %d\n", msg4.Get_available_size() );
287         }
288         if( strcmp( (char *) msg4.Get_payload().get(), wbuf ) != 0 ) {
289                 errors++;
290                 fprintf( stderr, "<FAIL> message copy builder payload of copy not the expected string\n" );
291         }
292
293         snprintf( wbuf, sizeof( wbuf ), "Rambling Wreck; GT!" );                // different string into msg 2 to ensure copy replaced msg3 string
294         strcpy( (char *) (msg2->Get_payload()).get(), wbuf );                   // populate the msg2 payload to vet copy
295         msg2->Set_len( strlen( wbuf ) );
296         *msg3 = *msg2;                                                                                                  // drive the copy operator= function
297         if( msg3->Get_available_size() != 2048 ) {
298                 errors++;
299                 fprintf( stderr, "<FAIL> message copy operator payload size smells: expected 2048, got %d\n", msg3->Get_available_size() );
300         }
301         if( strcmp( (char *) msg3->Get_payload().get(), wbuf ) != 0 ) {
302                 errors++;
303                 fprintf( stderr, "<FAIL> message copy builder payload of copy not the expected string\n" );
304         }
305
306         xapp::Message msg5 = std::move( *(msg3.get()) );                                        // drive move constructor
307         if( msg5.Get_available_size() != 2048 ) {
308                 errors++;
309                 fprintf( stderr, "<FAIL> message copy operator payload size smells: expected 2048, got %d\n", msg5.Get_available_size() );
310         }
311         if( strcmp( (char *) msg5.Get_payload().get(), wbuf ) != 0 ) {
312                 errors++;
313                 fprintf( stderr, "<FAIL> message copy builder payload of copy not the expected string\n" );
314         }
315
316         msg5.Set_len( 2 );                                      // bogus len for vetting later
317         msg5 = std::move( *(msg3.get()) );
318         if( msg5.Get_len() == 21 ) {
319                 errors++;
320                 fprintf( stderr, "<FAIL> message move operator payload len smells: expected 21, got %d\n", msg5.Get_len() );
321         }
322
323         // --------------------- alarm testing ------------------------------------------
324         std::shared_ptr<xapp::Alarm> a;
325
326         a = x->Alloc_alarm( );                                                  // drive all possible constructors through the framework
327         errors += fail_if( a == NULL, "unable to allcoate a generic alarm" );
328
329         setenv( "ALARM_MGR_SERVICE_NAME", "alarm_svc", 1 );
330         setenv( "ALARM_MGR_SERVICE_PORT", "9999", 1 );
331
332         a = x->Alloc_alarm( "meid-123" );
333         errors += fail_if( a == NULL, "unable to allcoate an alarm with just  meid" );
334
335         a = x->Alloc_alarm( 13, "meid-abc" );
336         errors += fail_if( a == NULL, "unable to allcoate an alarm with meid and  problem id" );
337
338         a->Set_meid( "changed_meid" );
339         for( i = 0; i < 6; i++ ) {
340                 a->Set_severity( i );                   // drive all switch possibilities
341         }
342
343         a->Set_appid( "new-appid" );
344         a->Set_problem( 99 );
345         a->Set_info( "new information string" );
346         a->Set_additional( "new additional information string" );
347
348         a->Dump();
349         errors += fail_if( !a->Raise(), "alarm raise with no parms failed" );
350         errors += fail_if( !a->Raise( xapp::Alarm::SEV_CRIT, 15, "problem string" ), "alarm raise s/p/i failed" );
351         errors += fail_if( !a->Raise( xapp::Alarm::SEV_CRIT, 15, "problem string", "addtl info" ), "alarm raise s/p/i/a failed" );
352
353         errors += fail_if( !a->Clear( ), "clear alarm failed" );
354         errors += fail_if( !a->Clear( xapp::Alarm::SEV_CRIT, 15, "problem string" ), "alarm clear s/p/i failed" );
355         errors += fail_if( !a->Clear( xapp::Alarm::SEV_CRIT, 15, "problem string", "addtl info" ), "alarm clear s/p/i/a failed" );
356         errors += fail_if( !a->Clear_all( ), "clear all failed" );
357
358         errors += fail_if( !a->Raise_again( ), "alarm raise again failed" );
359
360         xapp::Alarm b = *a.get();                               // force the move/copy operator functions to trigger
361         xapp::Alarm c( NULL );                                  // a useless alarm without a message
362         xapp::Alarm f( NULL, "meid" );                  // a useless alarm to drive direct construction
363         c = *a.get();                                                   // drive copy = operator
364
365         b = std::move( c );                                             // move = operator
366         xapp::Alarm d = std::move( b );                 // move constructor
367
368
369         // ------ minimal metrics to prove coverage ------------------------------------------------------------
370         metrics( x );
371
372         // ------------------------------------------------------------------------------------------------------
373
374         announce_results( errors );
375         return errors > 0;
376 }
377