cwFlowTest.cpp : Flow testing is now managed via cwTest.

This commit is contained in:
kevin 2024-05-29 12:33:13 -04:00
parent 9f00c88964
commit 3e8e0e2830

View File

@ -1,6 +1,7 @@
#include "cwCommon.h"
#include "cwLog.h"
#include "cwCommonImpl.h"
#include "cwTest.h"
#include "cwMem.h"
#include "cwText.h"
#include "cwNumericConvert.h"
@ -14,318 +15,61 @@
#include "cwFlowTest.h"
#include "cwFile.h"
#include "cwFileSys.h"
namespace cw
cw::rc_t cw::flow::test( const test::test_args_t& args )
{
namespace flow
rc_t rc = kOkRC;
const char* proc_cfg_fname = nullptr;
const char* subnet_cfg_fname = nullptr;
object_t* class_cfg = nullptr;
object_t* subnet_cfg = nullptr;
handle_t flowH;
if( args.module_args == nullptr )
{
typedef struct exec_test_str
{
void* logCbArg;
log::logOutputCbFunc_t logCbFunc;
file::handle_t logFileH;
} exec_test_t;
rc_t _compare_dirs( const char* dir0, const char* dir1, const char* test_name )
{
rc_t rc = kOkRC;
rc_t testRC = kOkRC;
unsigned dirRefN = 0;
filesys::dirEntry_t* dirRefA = nullptr;
char* testRefDir = nullptr;
unsigned testRefDirN = 0;
filesys::dirEntry_t* testRefDirA = nullptr;
unsigned testCnt = 0;
unsigned failCnt = 0;
// get a list of sub-directories in the ref. directory
if((dirRefA = filesys::dirEntries( dir0, filesys::kDirFsFl, &dirRefN )) == nullptr )
{
rc = cwLogError(kOpFailRC,"An error occurred while attempting to read the list of sub-directories in '%s'.",cwStringNullGuard(dir0));
goto errLabel;
}
// for each test
for(unsigned i=0; i<dirRefN; ++i)
if( dirRefA[i].name != nullptr && (test_name==nullptr || textIsEqual(dirRefA[i].name,test_name)) )
{
// form the test directory
if(( testRefDir = filesys::makeFn( dir0, nullptr, nullptr, dirRefA[i].name, nullptr )) == nullptr )
{
rc = cwLogError(kOpFailRC,"Test directory formation failed on '%s' and '%s'.",cwStringNullGuard(dir0),cwStringNullGuard(dirRefA[i].name));
goto errLabel;
}
// get the list of files in the test directory
if((testRefDirA = filesys::dirEntries( testRefDir, filesys::kFileFsFl, &testRefDirN )) == nullptr )
{
rc = cwLogError(kOpFailRC,"An error occurred while attempting to read the list of file from '%s'.",cwStringNullGuard(testRefDir));
goto errLabel;
}
testCnt += 1;
// for each file
for(unsigned j=0; rc==kOkRC && j<testRefDirN; ++j)
if( testRefDirA[j].name != nullptr )
{
char* testRefFn = filesys::makeFn( dir0, testRefDirA[j].name, nullptr, dirRefA[i].name, nullptr );
char* testCmpFn = filesys::makeFn( dir1, testRefDirA[j].name, nullptr, dirRefA[i].name, nullptr );
bool isEqualFl = false;
// compare two files
if((rc = file::compare( testRefFn, testCmpFn, isEqualFl)) != kOkRC )
rc = cwLogError(rc,"The comparison failed on '%s' == '%s'.",cwStringNullGuard(testRefFn),cwStringNullGuard(testCmpFn));
else
{
// if the test failed
if( !isEqualFl )
{
cwLogInfo("Test failed on: '%s'",testRefFn);
failCnt += 1;
}
}
mem::release(testRefFn);
mem::release(testCmpFn);
}
mem::release(testRefDirA);
mem::release(testRefDir);
}
mem::release(dirRefA);
errLabel:
mem::release(testRefDirA);
mem::release(testRefDir);
mem::release(dirRefA);
cwLogInfo("Tests:%i failed:%i",testCnt,failCnt);
return rc;
}
void _exec_test_log_cb( void* cbArg, unsigned level, const char* text )
{
rc_t rc;
exec_test_t* r = (exec_test_t*)cbArg;
if((rc = file::print(r->logFileH,text)) != kOkRC )
cwLogError(rc,"Log file write failed for '%s'.text");
if( r->logCbFunc != nullptr )
r->logCbFunc( r->logCbArg,level,text);
}
rc_t _exec_test( const object_t* class_cfg,
const object_t* subnet_cfg,
const object_t* test_cfg,
const char* proj_base_dir,
const char* test_case_label )
{
rc_t rc = kOkRC;
char* proj_dir = nullptr;
char* log_fname = nullptr;
exec_test_t test_recd;
handle_t flowH;
// save the log to a
test_recd.logCbArg = log::outputCbArg( log::globalHandle() );
test_recd.logCbFunc = log::outputCb( log::globalHandle() );
// form the projectory directory name
if((proj_dir = filesys::makeFn(proj_base_dir,nullptr,nullptr,test_case_label,nullptr)) == nullptr )
{
rc = cwLogError(kOpFailRC,"The project directory name could not be formed from '%s' and '%s'.",cwStringNullGuard(proj_base_dir),cwStringNullGuard(test_case_label));
goto errLabel;
}
// create the project directory
if( !filesys::isDir(proj_dir) )
{
if((rc = filesys::makeDir(proj_dir)) != kOkRC )
{
rc = cwLogError(kOpFailRC,"The project directory '%s' could not be created.",proj_dir);
goto errLabel;
}
}
// form the log file name
if((log_fname = filesys::makeFn( proj_dir, "log","txt",nullptr )) == nullptr )
{
rc = cwLogError(kOpFailRC,"The log file name could not be formed from the project directory.",cwStringNullGuard(proj_dir));
goto errLabel;
}
// open the log file
if((rc = file::open(test_recd.logFileH, log_fname,file::kWriteFl)) != kOkRC )
{
rc = cwLogError(rc,"The log file '%s' could not be created.",cwStringNullGuard(log_fname));
goto errLabel;
}
log::setOutputCb( log::globalHandle(), _exec_test_log_cb, &test_recd );
// create the flow object
if((rc = create( flowH, class_cfg, test_cfg, subnet_cfg, proj_dir)) != kOkRC )
{
rc = cwLogError(rc,"Flow object create failed.");
goto errLabel;
}
// run the network
if((rc = exec( flowH )) != kOkRC )
rc = cwLogError(rc,"Execution failed.");
// destroy the flow object
if((rc = destroy(flowH)) != kOkRC )
{
rc = cwLogError(rc,"Close the flow object.");
goto errLabel;
}
errLabel:
file::close(test_recd.logFileH);
log::setOutputCb( log::globalHandle(), test_recd.logCbFunc, test_recd.logCbArg );
mem::release(log_fname);
mem::release(proj_dir);
return rc;
}
}
}
cw::rc_t cw::flow::test( const object_t* cfg, int argc, const char* argv[] )
{
rc_t rc = kOkRC;
const char* proc_cfg_fname = nullptr;
const char* subnet_cfg_fname = nullptr;
const object_t* test_cases_cfg = nullptr;
object_t* class_cfg = nullptr;
object_t* subnet_cfg = nullptr;
const object_t* test_cfg = nullptr;
const char* proj_dir = nullptr;
const char* test_ref_dir = nullptr;
bool cmp_enable_fl = false;
const char* test_name = nullptr;
bool test_all_fl = false;
if( argc < 2 || textLength(argv[1]) == 0 )
{
rc = cwLogError(kInvalidArgRC,"No 'test-case' label was given on the command line.");
rc = cwLogError(kInvalidArgRC,"The flow test cases require module args.");
goto errLabel;
}
test_name = argv[1];
test_all_fl = textIsEqual(test_name,"all");
if((rc = cfg->getv("proc_cfg_fname",proc_cfg_fname,
"test_cases", test_cases_cfg,
"project_dir", proj_dir)) != kOkRC )
if((rc = args.module_args->readv("proc_cfg_fname",0,proc_cfg_fname,
"subnet_cfg_fname",0,subnet_cfg_fname)) != kOkRC )
{
rc = cwLogError(rc,"The name of the flow_proc_dict file could not be parsed.");
rc = cwLogError(rc,"Flow module arg's parse failed.");
goto errLabel;
}
// was 'compare' requested
if( argc > 2 && textLength(argv[2])!=0 and textIsEqual(argv[2],"compare") )
cmp_enable_fl = true;
// get the subnet cfg filename
if((rc = cfg->getv_opt("subnet_cfg_fname",subnet_cfg_fname,
"test_ref_dir",test_ref_dir)) != kOkRC )
{
rc = cwLogError(rc,"The name of the subnet file could not be parsed.");
goto errLabel;
}
// parse the proc dict. file
if((rc = objectFromFile(proc_cfg_fname,class_cfg)) != kOkRC )
{
rc = cwLogError(rc,"The proc dictionary could not be read from '%s'.",cwStringNullGuard(proc_cfg_fname));
rc = cwLogError(rc,"The flow proc dictionary could not be read from '%s'.",cwStringNullGuard(proc_cfg_fname));
goto errLabel;
}
// parse the subnet dict file
if((rc = objectFromFile(subnet_cfg_fname,subnet_cfg)) != kOkRC )
{
rc = cwLogError(rc,"The subnet dictionary could not be read from '%s'.",cwStringNullGuard(subnet_cfg_fname));
rc = cwLogError(rc,"The flow subnet dictionary could not be read from '%s'.",cwStringNullGuard(subnet_cfg_fname));
goto errLabel;
}
// validate the project directory
if( proj_dir!=nullptr && !filesys::isDir(proj_dir) )
// create the flow object
if((rc = create( flowH, class_cfg, args.test_args, subnet_cfg, args.out_dir)) != kOkRC )
{
if((rc = filesys::makeDir(proj_dir)) != kOkRC )
{
rc = cwLogError(rc,"The project directory '%s' could not be created.",cwStringNullGuard(proj_dir));
}
rc = cwLogError(rc,"Flow object create failed.");
goto errLabel;
}
// for each test
for(unsigned i=0; i<test_cases_cfg->child_count(); ++i)
// run the network
if((rc = exec( flowH )) != kOkRC )
rc = cwLogError(rc,"Execution failed.");
errLabel:
// destroy the flow object
if((rc = destroy(flowH)) != kOkRC )
{
const object_t* test_cfg_pair = test_cases_cfg->child_ele(i);
const char* test_label = nullptr;
bool is_test_disabled_fl = false;
// validate the test cfg pair
if(test_cfg_pair == nullptr || !test_cfg_pair->is_pair() || (test_label = test_cfg_pair->pair_label()) == nullptr || (test_cfg=test_cfg_pair->pair_value())==nullptr || !test_cfg->is_dict())
{
rc = cwLogError(kSyntaxErrorRC,"A syntax error was encountered on the test at index %i (%s).",i,cwStringNullGuard(test_label));
goto errLabel;
}
// get the 'disabled flag'
if((rc = test_cfg->getv_opt("testDisableFl",is_test_disabled_fl)) != kOkRC )
{
rc = cwLogError(kSyntaxErrorRC,"An error occurred while parsing the 'testDisableFl'.");
goto errLabel;
}
// if this test is disabled
if( is_test_disabled_fl )
{
if( !test_all_fl )
{
rc = cwLogError(kInvalidArgRC,"The requested test '%s' is disabled.",test_label);
goto errLabel;
}
continue;
}
// if we are testing all test or this specific test
if( test_all_fl || textIsEqual(test_name,test_label) )
{
if((rc = _exec_test(class_cfg,subnet_cfg,test_cfg,proj_dir,test_label)) != kOkRC )
{
rc = cwLogError(kOpFailRC,"Test execution failed on '%s'.",cwStringNullGuard(test_label));
goto errLabel;
}
if( !test_all_fl )
break;
}
rc = cwLogError(rc,"Close the flow object.");
goto errLabel;
}
// if comparision is enabled
if( test_ref_dir != nullptr && cmp_enable_fl )
{
const char* sel_test_name = test_all_fl ? nullptr : test_name;
_compare_dirs( test_ref_dir, proj_dir, sel_test_name );
}
errLabel:
if( class_cfg != nullptr )
class_cfg->free();
@ -333,4 +77,5 @@ cw::rc_t cw::flow::test( const object_t* cfg, int argc, const char* argv[] )
subnet_cfg->free();
return rc;
}