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