/*
Mnemonic: Unit_test.cpp
- Abstract: This is the unit test driver for the C++ xAPP framework
+ Abstract: This is the unit test driver for the C++ xAPP framework. It
+ operates by including all of the modules directly (in order
+ to build them with the necessary coverage flags), then
+ drives all that it can. The RMR emulation module provides
+ emulated RMR functions which simulate the creation, sending
+ and receiving of messages etc.
Date: 20 March 2020
- Author: E. Scott Daniels
+ Author: E. Scott Daniels
*/
#include <memory>
#include "../src/messaging/message.hpp"
#include "../src/messaging/messenger.hpp"
#include "../src/messaging/msg_component.hpp"
+#include "../src/alarm/alarm.hpp"
+#include "../src/metrics/metrics.hpp"
#include "../src/xapp/xapp.hpp"
#include "../src/messaging/callback.cpp"
#include "../src/messaging/default_cb.cpp"
#include "../src/messaging/message.cpp"
#include "../src/messaging/messenger.cpp"
+#include "../src/alarm/alarm.cpp"
#include "../src/xapp/xapp.cpp"
-// callback error counts are global for ease
+#include "ut_support.cpp"
+
+// ---------------------------------------------------------------------------------------------
+/*
+ callback error counts are global for ease. They track the number of times each callback
+ was invoked with the expected message type(s) and any times they were not.
+*/
int err_cb1 = 0;
int err_cb2 = 0;
int err_cbd = 0;
int good_cbd = 0;
/*
- callback functions to register; driven as we "receive" messages (the RMR emulation package
+ callback functions to register; driven as we "receive" messages (the RMR emulation package
will generate a message every time the receive function is called).
*/
-void cb1( Message& mbuf, int mtype, int subid, int len, Msg_component payload, void* data ) {
+void cb1( xapp::Message& mbuf, int mtype, int subid, int len, xapp::Msg_component payload, void* data ) {
if( mtype != 1 ) { // should only be driven for type 1 messages
err_cb1++;
} else {
good_cb1++;
}
}
-void cb2( Message& mbuf, int mtype, int subid, int len, Msg_component payload, void* data ) {
+void cb2( xapp::Message& mbuf, int mtype, int subid, int len, xapp::Msg_component payload, void* data ) {
if( mtype != 2 ) { // should only be driven for type 2 messages
err_cb2++;
} else {
good_cb2++;
}
}
-void cbd( Message& mbuf, int mtype, int subid, int len, Msg_component payload, void* data ) {
- if( mtype > 0 && mtype < 3 ) { // should only be driven for types that arent 1 or 2
+void cbd( xapp::Message& mbuf, int mtype, int subid, int len, xapp::Msg_component payload, void* data ) {
+ if( mtype > 0 && mtype < 3 ) { // should only be driven for types that arent 1 or 2
if( err_cbd < 10 ) {
fprintf( stderr, "<FAIL> cbd: bad message type: %d\n", mtype );
}
}
}
+/*
+ The Xapp Run() function only returns when Xapp is asked to stop, and that
+ isn't supported from inside any of the callbacks. This funciton is
+ started in a thread and after a few seconds it will drive the halt
+ function in the Xapp instance to stop the run function and allow the
+ unit test to finish.
+*/
void killer( std::shared_ptr<Xapp> x ) {
- fprintf( stderr, ">>>> killer is waiting in the shadows\n" );
- sleep( 5 );
- fprintf( stderr, ">>>> killer is on the loose\n" );
+ fprintf( stderr, "<INFO> killer is waiting in the shadows\n" );
+ sleep( 2 );
+ fprintf( stderr, "<INFO> killer is on the loose\n" );
x->Halt();
}
+/*
+ Drive the constructors so that we actually see the coverage
+ in the .gc* files. The metrics tests will actually verify that
+ the various underlying functions work.
+*/
+static int metrics( std::shared_ptr<Xapp> x ) {
+ std::shared_ptr<xapp::Metrics> m;
+
+ m = x->Alloc_metrics( ); // basic construction
+ m = x->Alloc_metrics( "different-source" ); // drive alternate builders
+ m = x->Alloc_metrics( "different-app", "different-source" );
+}
+
int main( int argc, char** argv ) {
std::thread* tinfo; // we'll start a thread that will shut things down after a few seconds
- std::unique_ptr<Message> msg;
+ std::unique_ptr<xapp::Message> msg;
std::shared_ptr<Xapp> x;
- Msg_component payload;
+ xapp::Msg_component payload;
std::unique_ptr<unsigned char> ucs;
unsigned char* new_payload;
std::shared_ptr<unsigned char> new_p_ref; // reference to payload to pass to send functions
int ai = 1; // arg processing index
int nthreads = 2; // ensure the for loop is executed in setup
int i;
+ int len;
int errors = 0;
+ char wbuf[256];
ai = 1;
while( ai < argc ) { // very simple flag processing (no bounds/error checking)
}
switch( argv[ai][1] ) { // we only support -x so -xy must be -x -y
- case 'p':
- port = argv[ai+1];
+ case 'p':
+ port = argv[ai+1];
ai++;
break;
ai++;
}
-
+
+ set_test_name( "unit_test" );
+
+ // ------------------- generic xapp tests ----------------------------------------------
x = std::shared_ptr<Xapp>( new Xapp( port, true ) );
x->Add_msg_cb( 1, cb1, NULL );
x->Add_msg_cb( 2, cb2, NULL );
errors++;
}
+ // ----- specific move/copy coverage drivers ---------------------------
+
+ xapp::Messenger m1( (char *) "1234", false ); // messenger class does NOT permit copies, so no need to test
+ xapp::Messenger m2( (char *) "9999", false );
+ m1 = std::move( m2 ); // drives move operator= function
+ xapp::Messenger m3 = std::move( m1 ); // drives move constructor function
+
+ std::unique_ptr<xapp::Message> msg2 = x->Alloc_msg( 2048 );
+ std::unique_ptr<xapp::Message> msg3 = x->Alloc_msg( 4096 );
+
+ snprintf( wbuf, sizeof( wbuf ), "Stand up and cheer!!" );
+ msg3->Set_len( strlen( wbuf ) );
+ strcpy( (char *) (msg3->Get_payload()).get(), wbuf ); // populate the payload to vet copy later
+ fprintf( stderr, "<DBUG> set string (%s) \n", (char *) (msg3->Get_payload()).get() );
+
+ xapp::Message msg4 = *(msg3.get()); // drive copy builder; msg4 should have a 4096 byte payload
+ fprintf( stderr, "<DBUG> copy string (%s) \n", (char *) (msg4.Get_payload()).get() ); // and payload should be coppied
+ if( msg4.Get_available_size() != 4096 ) {
+ errors++;
+ fprintf( stderr, "<FAIL> message copy builder payload size smells: expected 4096, got %d\n", msg4.Get_available_size() );
+ }
+ if( strcmp( (char *) msg4.Get_payload().get(), wbuf ) != 0 ) {
+ errors++;
+ fprintf( stderr, "<FAIL> message copy builder payload of copy not the expected string\n" );
+ }
+
+ snprintf( wbuf, sizeof( wbuf ), "Rambling Wreck; GT!" ); // different string into msg 2 to ensure copy replaced msg3 string
+ strcpy( (char *) (msg2->Get_payload()).get(), wbuf ); // populate the msg2 payload to vet copy
+ msg2->Set_len( strlen( wbuf ) );
+ *msg3 = *msg2; // drive the copy operator= function
+ if( msg3->Get_available_size() != 2048 ) {
+ errors++;
+ fprintf( stderr, "<FAIL> message copy operator payload size smells: expected 2048, got %d\n", msg3->Get_available_size() );
+ }
+ if( strcmp( (char *) msg3->Get_payload().get(), wbuf ) != 0 ) {
+ errors++;
+ fprintf( stderr, "<FAIL> message copy builder payload of copy not the expected string\n" );
+ }
+
+ xapp::Message msg5 = std::move( *(msg3.get()) ); // drive move constructor
+ if( msg5.Get_available_size() != 2048 ) {
+ errors++;
+ fprintf( stderr, "<FAIL> message copy operator payload size smells: expected 2048, got %d\n", msg5.Get_available_size() );
+ }
+ if( strcmp( (char *) msg5.Get_payload().get(), wbuf ) != 0 ) {
+ errors++;
+ fprintf( stderr, "<FAIL> message copy builder payload of copy not the expected string\n" );
+ }
+
+ msg5.Set_len( 2 ); // bogus len for vetting later
+ msg5 = std::move( *(msg3.get()) );
+ if( msg5.Get_len() == 21 ) {
+ errors++;
+ fprintf( stderr, "<FAIL> message move operator payload len smells: expected 21, got %d\n", msg5.Get_len() );
+ }
+
+ // --------------------- alarm testing ------------------------------------------
+ std::shared_ptr<xapp::Alarm> a;
+
+ a = x->Alloc_alarm( ); // drive all possible constructors through the framework
+ errors += fail_if( a == NULL, "unable to allcoate a generic alarm" );
+
+ setenv( "ALARM_MGR_SERVICE_NAME", "alarm_svc", 1 );
+ setenv( "ALARM_MGR_SERVICE_PORT", "9999", 1 );
+
+ a = x->Alloc_alarm( "meid-123" );
+ errors += fail_if( a == NULL, "unable to allcoate an alarm with just meid" );
+
+ a = x->Alloc_alarm( 13, "meid-abc" );
+ errors += fail_if( a == NULL, "unable to allcoate an alarm with meid and problem id" );
+
+ a->Set_meid( "changed_meid" );
+ for( i = 0; i < 6; i++ ) {
+ a->Set_severity( i ); // drive all switch possibilities
+ }
+
+ a->Set_appid( "new-appid" );
+ a->Set_problem( 99 );
+ a->Set_info( "new information string" );
+ a->Set_additional( "new additional information string" );
+
+ a->Dump();
+ errors += fail_if( !a->Raise(), "alarm raise with no parms failed" );
+ errors += fail_if( !a->Raise( xapp::Alarm::SEV_CRIT, 15, "problem string" ), "alarm raise s/p/i failed" );
+ errors += fail_if( !a->Raise( xapp::Alarm::SEV_CRIT, 15, "problem string", "addtl info" ), "alarm raise s/p/i/a failed" );
+
+ errors += fail_if( !a->Clear( ), "clear alarm failed" );
+ errors += fail_if( !a->Clear( xapp::Alarm::SEV_CRIT, 15, "problem string" ), "alarm clear s/p/i failed" );
+ errors += fail_if( !a->Clear( xapp::Alarm::SEV_CRIT, 15, "problem string", "addtl info" ), "alarm clear s/p/i/a failed" );
+ errors += fail_if( !a->Clear_all( ), "clear all failed" );
+
+ errors += fail_if( !a->Raise_again( ), "alarm raise again failed" );
+
+ xapp::Alarm b = *a.get(); // force the move/copy operator functions to trigger
+ xapp::Alarm c( NULL ); // a useless alarm without a message
+ xapp::Alarm f( NULL, "meid" ); // a useless alarm to drive direct construction
+ c = *a.get(); // drive copy = operator
+
+ b = std::move( c ); // move = operator
+ xapp::Alarm d = std::move( b ); // move constructor
+
+ // ------ minimal metrics to prove coverage ------------------------------------------------------------
+ metrics( x );
+
+ // ------------------------------------------------------------------------------------------------------
+
+ announce_results( errors );
return errors > 0;
}
+