1 // vim: ts=4 sw=4 noet :
3 ==================================================================================
4 Copyright (c) 2020 Nokia
5 Copyright (c) 2020 AT&T Intellectual Property.
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
11 http://www.apache.org/licenses/LICENSE-2.0
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 ==================================================================================
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.
31 Author: E. Scott Daniels
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"
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"
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.
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).
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
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
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
83 fprintf( stderr, "<FAIL> cbd: bad message type: %d\n", mtype );
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
98 void killer( std::shared_ptr<Xapp> x ) {
99 fprintf( stderr, "<INFO> killer is waiting in the shadows\n" );
101 fprintf( stderr, "<INFO> killer is on the loose\n" );
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
122 while( ai < argc ) { // very simple flag processing (no bounds/error checking)
123 if( argv[ai][0] != '-' ) {
127 switch( argv[ai][1] ) { // we only support -x so -xy must be -x -y
134 nthreads = atoi( argv[ai+1] );
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 );
147 msg = x->Alloc_msg( 2048 );
148 payload = msg->Get_payload();
150 msg->Set_mtype( 100 );
151 msg->Set_subid( -10 );
153 ucs = msg->Copy_payload( );
155 fprintf( stderr, "<FAIL> expected pointer to copy payload but got nil\n" );
159 ucs = msg->Get_meid();
161 fprintf( stderr, "<FAIL> expected pointer to meid copy but got nil\n" );
165 ucs = msg->Get_src();
167 fprintf( stderr, "<FAIL> expected pointer to src copy but got nil\n" );
171 i = msg->Get_available_size();
173 fprintf( stderr, "<FAIL> len expected payload avail size of 2048 but got %d\n", i );
177 i = msg->Get_mtype();
179 fprintf( stderr, "<FAIL> expected mtype of 100 but got %d\n", i );
183 i = msg->Get_state( );
185 fprintf( stderr, "<FAIL> expected state of 0 but got %d\n", i );
189 i = msg->Get_subid();
191 fprintf( stderr, "<FAIL> expected subid of -10 but got %d\n", i );
197 fprintf( stderr, "<FAIL> len expected 128 but got %d\n", i );
201 msg->Send(); // generic send as is functions
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
208 msg->Set_meid( new_p_ref );
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
216 msg->Set_mtype( 100 );
217 msg->Set_subid( -10 );
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 );
225 msg = NULL; // should drive the message destroyer for coverage
227 msg = x->Receive( 2000 );
229 fprintf( stderr, "<FAIL> expected message from receive but got nil\n" );
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 );
237 x->Halt(); // drive for coverage
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 );
245 // ----- specific move/copy coverage drivers ---------------------------
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
252 std::unique_ptr<Message> msg2 = x->Alloc_msg( 2048 );
253 std::unique_ptr<Message> msg3 = x->Alloc_msg( 4096 );
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() );
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 ) {
264 fprintf( stderr, "<FAIL> message copy builder payload size smells: expected 4096, got %d\n", msg4.Get_available_size() );
266 if( strcmp( (char *) msg4.Get_payload().get(), wbuf ) != 0 ) {
268 fprintf( stderr, "<FAIL> message copy builder payload of copy not the expected string\n" );
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 ) {
277 fprintf( stderr, "<FAIL> message copy operator payload size smells: expected 2048, got %d\n", msg3->Get_available_size() );
279 if( strcmp( (char *) msg3->Get_payload().get(), wbuf ) != 0 ) {
281 fprintf( stderr, "<FAIL> message copy builder payload of copy not the expected string\n" );
284 Message msg5 = std::move( *(msg3.get()) ); // drive move constructor
285 if( msg5.Get_available_size() != 2048 ) {
287 fprintf( stderr, "<FAIL> message copy operator payload size smells: expected 2048, got %d\n", msg5.Get_available_size() );
289 if( strcmp( (char *) msg5.Get_payload().get(), wbuf ) != 0 ) {
291 fprintf( stderr, "<FAIL> message copy builder payload of copy not the expected string\n" );
294 msg5.Set_len( 2 ); // bogus len for vetting later
295 msg5 = std::move( *(msg3.get()) );
296 if( msg5.Get_len() == 21 ) {
298 fprintf( stderr, "<FAIL> message move operator payload len smells: expected 21, got %d\n", msg5.Get_len() );