Module: sems Branch: master Commit: 1fd9c544f6ae1ab6a98d4ed9c16baf37a19e02a6 URL: http://git.sip-router.org/cgi-bin/gitweb.cgi/sems/?a=commit;h=1fd9c544f6ae1ab6a98d4ed9c16baf37a19e02a6
Author: Stefan Sayer <[email protected]> Committer: Stefan Sayer <[email protected]> Date: Mon Jul 5 18:30:18 2010 +0200 rough consistency check for DSMs after loading - check for initial state - check for existence of destination states - check whether hangup is handled in all states --- apps/dsm/DSM.cpp | 11 +++-- apps/dsm/DSM.h | 1 + apps/dsm/DSMStateDiagramCollection.cpp | 15 +++++++- apps/dsm/DSMStateDiagramCollection.h | 2 +- apps/dsm/DSMStateEngine.cpp | 65 ++++++++++++++++++++++++++++++++ apps/dsm/DSMStateEngine.h | 5 ++ apps/dsm/etc/dsm.conf | 4 ++ 7 files changed, 97 insertions(+), 6 deletions(-) diff --git a/apps/dsm/DSM.cpp b/apps/dsm/DSM.cpp index 3213ab6..31689dc 100644 --- a/apps/dsm/DSM.cpp +++ b/apps/dsm/DSM.cpp @@ -63,6 +63,7 @@ DSMFactory* DSMFactory::instance() bool DSMFactory::DebugDSM; string DSMFactory::InboundStartDiag; string DSMFactory::OutboundStartDiag; +bool DSMFactory::CheckDSM; #ifdef USE_MONITORING bool DSMFactory::MonitoringFullCallgraph; @@ -72,6 +73,7 @@ MonSelectType DSMFactory::MonSelectCaller; MonSelectType DSMFactory::MonSelectCallee; string DSMFactory::MonSelectFallback; + #endif // USE_MONITORING DSMFactory::DSMFactory(const string& _app_name) @@ -122,6 +124,7 @@ int DSMFactory::onLoad() configureModule(cfg); DebugDSM = cfg.getParameter("debug_raw_dsm") == "yes"; + CheckDSM = cfg.getParameter("dsm_consistency_check", "yes") == "yes"; if (!loadPrompts(cfg)) return -1; @@ -327,7 +330,7 @@ bool DSMFactory::loadDiags(AmConfigReader& cfg, DSMStateDiagramCollection* m_dia vector<string> diags_names = explode(LoadDiags, ","); for (vector<string>::iterator it= diags_names.begin(); it != diags_names.end(); it++) { - if (!m_diags->loadFile(DiagPath+*it+".dsm", *it, ModPath, DebugDSM)) { + if (!m_diags->loadFile(DiagPath+*it+".dsm", *it, ModPath, DebugDSM, CheckDSM)) { ERROR("loading %s from %s\n", it->c_str(), (DiagPath+*it+".dsm").c_str()); return false; @@ -743,7 +746,7 @@ void DSMFactory::reloadDSMs(const AmArg& args, AmArg& ret) { vector<string> diags_names = explode(LoadDiags, ","); for (vector<string>::iterator it= diags_names.begin(); it != diags_names.end(); it++) { - if (!new_diags->loadFile(DiagPath+*it+".dsm", *it, ModPath, DebugDSM)) { + if (!new_diags->loadFile(DiagPath+*it+".dsm", *it, ModPath, DebugDSM, CheckDSM)) { ERROR("loading %s from %s\n", it->c_str(), (DiagPath+*it+".dsm").c_str()); ret.push(500); @@ -949,7 +952,7 @@ void DSMFactory::loadDSM(const AmArg& args, AmArg& ret) { ret.push(400); ret.push("DSM named '" + dsm_name + "' already loaded (use reloadDSMs to reload all)"); } else { - if (!MainScriptConfig.diags->loadFile(dsm_file_name, dsm_name, ModPath, DebugDSM)) { + if (!MainScriptConfig.diags->loadFile(dsm_file_name, dsm_name, ModPath, DebugDSM, CheckDSM)) { ret.push(500); ret.push("error loading "+dsm_name+" from "+ dsm_file_name); } else { @@ -976,7 +979,7 @@ void DSMFactory::loadDSMWithPaths(const AmArg& args, AmArg& ret) { ret.push(400); ret.push("DSM named '" + dsm_name + "' already loaded (use reloadDSMs to reload all)"); } else { - if (!MainScriptConfig.diags->loadFile(diag_path+dsm_name+".dsm", dsm_name, mod_path, DebugDSM)) { + if (!MainScriptConfig.diags->loadFile(diag_path+dsm_name+".dsm", dsm_name, mod_path, DebugDSM, CheckDSM)) { ret.push(500); ret.push("error loading "+dsm_name+" from "+ diag_path+dsm_name+".dsm"); } else { diff --git a/apps/dsm/DSM.h b/apps/dsm/DSM.h index e5e1d06..f5bee93 100644 --- a/apps/dsm/DSM.h +++ b/apps/dsm/DSM.h @@ -67,6 +67,7 @@ class DSMFactory std::set<DSMStateDiagramCollection*> old_diags; static bool DebugDSM; + static bool CheckDSM; static string InboundStartDiag; static string OutboundStartDiag; diff --git a/apps/dsm/DSMStateDiagramCollection.cpp b/apps/dsm/DSMStateDiagramCollection.cpp index 9124e5e..416b89a 100644 --- a/apps/dsm/DSMStateDiagramCollection.cpp +++ b/apps/dsm/DSMStateDiagramCollection.cpp @@ -37,7 +37,7 @@ DSMStateDiagramCollection::~DSMStateDiagramCollection() { } bool DSMStateDiagramCollection::loadFile(const string& filename, const string& name, - const string& mod_path, bool debug_dsm) { + const string& mod_path, bool debug_dsm, bool check_dsm) { DBG("loading DSM '%s' from '%s'\n", name.c_str(), filename.c_str()); DSMChartReader cr; @@ -70,6 +70,19 @@ bool DSMStateDiagramCollection::loadFile(const string& filename, const string& n ERROR("DonkeySM decode script error!\n"); return false; } + if (check_dsm) { + string report; + if (!diags.back().checkConsistency(report)) { + WARN("consistency check failed on '%s' from file '%s':\n", + name.c_str(), filename.c_str()); + WARN("------------------------------------------\n" + "%s\n" + "------------------------------------------\n", report.c_str()); + } else { + DBG("DSM '%s' passed consistency check\n", name.c_str()); + } + } + return true; } diff --git a/apps/dsm/DSMStateDiagramCollection.h b/apps/dsm/DSMStateDiagramCollection.h index b619f01..a167ccb 100644 --- a/apps/dsm/DSMStateDiagramCollection.h +++ b/apps/dsm/DSMStateDiagramCollection.h @@ -44,7 +44,7 @@ class DSMStateDiagramCollection ~DSMStateDiagramCollection(); bool loadFile(const string& filename, const string& name, - const string& mod_path, bool debug_dsm); + const string& mod_path, bool debug_dsm, bool check_dsm); void addToEngine(DSMStateEngine* e); bool hasDiagram(const string& name); vector<string> getDiagramNames(); diff --git a/apps/dsm/DSMStateEngine.cpp b/apps/dsm/DSMStateEngine.cpp index 82b11f5..7769d11 100644 --- a/apps/dsm/DSMStateEngine.cpp +++ b/apps/dsm/DSMStateEngine.cpp @@ -139,6 +139,70 @@ State* DSMStateDiagram::getInitialState() { } +bool DSMStateDiagram::checkConsistency(string& report) { + bool res = true; + DBG("checking consistency of '%s'\n", name.c_str()); + res &= checkInitialState(report); + res &= checkDestinationStates(report); + res &= checkHangupHandled(report); + return res; +} + +bool DSMStateDiagram::checkInitialState(string& report) { + DBG("checking for initial state...\n"); + if (NULL == getInitialState()) { + report+=name+": " "No initial state defined!\n"; + return false; + } + return true; +} +bool DSMStateDiagram::checkDestinationStates(string& report) { + DBG("checking for existence of destination states...\n"); + bool res = true; + for (vector<State>::iterator it= + states.begin(); it != states.end(); it++) { + for (vector<DSMTransition>::iterator t_it= + it->transitions.begin(); t_it != it->transitions.end(); t_it++) { + if (NULL == getState(t_it->to_state)) { + report += name+": State '"+it->name+"' Transition '"+t_it->name+ + "' : Destination state '"+ t_it->to_state +"' is not defined\n"; + res = false; + } + } + } + return res; +} + +bool DSMStateDiagram::checkHangupHandled(string& report) { + DBG("checking for hangup handled in all states...\n"); + bool res = true; + for (vector<State>::iterator it= + states.begin(); it != states.end(); it++) { + bool have_hangup_trans = false; + for (vector<DSMTransition>::iterator t_it= + it->transitions.begin(); t_it != it->transitions.end(); t_it++) { + for (vector<DSMCondition*>::iterator c_it= + t_it->precond.begin(); c_it!=t_it->precond.end(); c_it++) { + if ((*c_it)->type == DSMCondition::Hangup) { + // todo: what if other conditions unmet? + have_hangup_trans = true; + break; + } + } + if (have_hangup_trans) + break; + + } + if (!have_hangup_trans) { + report += name+": State '"+it->name+"': hangup is not handled\n"; + res = false; + } + } + + return res; +} + + DSMStateEngine::DSMStateEngine() : current(NULL) { } @@ -492,3 +556,4 @@ void varPrintArg(const AmArg& a, map<string, string>& dst, const string& name) { default: dst[name] = "<UNKONWN TYPE>"; return; } } + diff --git a/apps/dsm/DSMStateEngine.h b/apps/dsm/DSMStateEngine.h index e0882c2..1f0023e 100644 --- a/apps/dsm/DSMStateEngine.h +++ b/apps/dsm/DSMStateEngine.h @@ -161,6 +161,10 @@ class DSMStateDiagram { string name; string initial_state; + bool checkInitialState(string& report); + bool checkDestinationStates(string& report); + bool checkHangupHandled(string& report); + public: DSMStateDiagram(const string& name); ~DSMStateDiagram(); @@ -171,6 +175,7 @@ class DSMStateDiagram { void addState(const State& state, bool is_initial = false); bool addTransition(const DSMTransition& trans); const string& getName() { return name; } + bool checkConsistency(string& report); }; class DSMException { diff --git a/apps/dsm/etc/dsm.conf b/apps/dsm/etc/dsm.conf index f312196..102771e 100644 --- a/apps/dsm/etc/dsm.conf +++ b/apps/dsm/etc/dsm.conf @@ -16,6 +16,10 @@ mod_path=/usr/local/lib/sems/dsm/ # print raw DSM text while loading to debug log? # debug_raw_dsm=yes +# do rough consistency checking after loading DSM? +# (default: yes) +#dsm_consistency_check=no + # DSM to start for in/outbound call if application to execute=dsm # (from application=xyz in sems.conf, either application=dsm or # application=$(apphdr)/$(ruriparam) etc) _______________________________________________ Semsdev mailing list [email protected] http://lists.iptel.org/mailman/listinfo/semsdev
