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

Reply via email to