Fork variant for TestStep command
authorEduardo Ramos Testillano <eduardo.ramos.testillano@ericsson.com>
Sun, 4 Oct 2015 17:47:30 +0000 (19:47 +0200)
committerEduardo Ramos Testillano <eduardo.ramos.testillano@ericsson.com>
Sun, 4 Oct 2015 17:47:30 +0000 (19:47 +0200)
example/diameter/launcher/Launcher.cpp
example/diameter/launcher/testing/TestManager.cpp
example/diameter/launcher/testing/TestStep.cpp
example/diameter/launcher/testing/TestStep.hpp

index eac8b26..ff86f46 100644 (file)
@@ -1896,7 +1896,7 @@ void Launcher::eventOperation(const std::string &operation, std::string &respons
       else {
         if (id == -1) {
           bool anyReset = testManager.resetPool((param2 == "hard") ? true:false);
-          opt_response_content = "reset have been sent to all programmed tests: "; opt_response_content += anyReset ? "some/all was actually reset" : "nothing was reset";
+          opt_response_content = "reset have been sent to all programmed tests: "; opt_response_content += anyReset ? "some/all have been reset" : "nothing was reset";
         }
         else {
           opt_response_content = "cannot found test id (";
index 38916d0..6dfec1e 100644 (file)
@@ -221,8 +221,8 @@ bool TestManager::resetPool(bool hard) throw() {
 
   if (!tests()) return result;
   for (test_pool_nc_it it = a_testPool.begin(); it != a_testPool.end(); it++) {
-    it->second->reset(hard);
-    result = true;
+    if (it->second->reset(hard))
+      result = true;
   }
   //a_sessionIdTestCaseMap.clear();
   return result;
index c1f27d8..75ede74 100644 (file)
 #include <stdlib.h>    // exit
 #include <sys/wait.h>  // waitpid, pid_t, WNOHANG
 
+// cmd with fork:
+#include <sys/types.h>
+#include <unistd.h>
+
+
 // Project
 #include <anna/xml/Compiler.hpp>
 #include <anna/core/util/Millisecond.hpp>
@@ -57,19 +62,19 @@ namespace {
     sa.sa_flags = SA_RESTART | SA_NOCLDSTOP;
     if (sigaction(SIGCHLD, &sa, 0) != -1) {
       status = system(cmd.c_str());
-     /* POPEN version:
-      char readbuf[256];
-      FILE *fp = popen(cmd.c_str(), "r");
-      if (fp) {
-        while(fgets(readbuf, sizeof(readbuf), fp))
-          step->appendOutput("\n");
-          step->appendOutput(readbuf);
-          status = pclose(fp);
-      }
-      else {
-        status = -1;
-      }
-      */
+      /* POPEN version:
+          char readbuf[256];
+          FILE *fp = popen(cmd.c_str(), "r");
+          if (fp) {
+            while(fgets(readbuf, sizeof(readbuf), fp))
+              step->appendOutput("\n");
+              step->appendOutput(readbuf);
+              status = pclose(fp);
+          }
+          else {
+            status = -1;
+          }
+       */
     }
     else {
       perror(0);
@@ -92,6 +97,54 @@ namespace {
     // TODO: mutex the step while setting data here !!
   }
 
+  void cmdRunOnThreadWithFork (TestStepCmd *step, const std::string &cmd) {
+
+    // Thread running:
+    step->setThreadRunning(true);
+
+    pid_t cpid, w;
+    int status = -2;
+
+    if ((cpid = fork()) < 0) {
+      step->setErrorMsg("Error in fork()");
+    }
+    else if (cpid == 0) {
+      // child
+      status = system(cmd.c_str());
+      _exit(WEXITSTATUS(status));
+    }
+    else {
+      // parent
+      step->setChildPid(cpid);
+      do {
+        w = waitpid(cpid, &status, WUNTRACED | WCONTINUED);
+        if (w != -1) {
+
+          if (WIFEXITED(status)) {
+            step->setResultCode(WEXITSTATUS(status)); // rc = status >>= 8; // divide by 256
+            break;
+          }
+          else if (WIFSIGNALED(status)) {
+            step->setErrorMsg(anna::functions::asString("killed by signal %d", WTERMSIG(status)));
+            step->setResultCode(128 + WTERMSIG(status));
+            break;
+          } else if (WIFSTOPPED(status)) {
+            step->setErrorMsg(anna::functions::asString("stopped by signal %d", WSTOPSIG(status)));
+          } else if (WIFCONTINUED(status)) {
+            step->setErrorMsg("continued");
+          }
+        }
+        else {
+          step->setErrorMsg("waitpid error");
+          step->setResultCode(-1);
+          break;
+        }
+      } while (!WIFEXITED(status) && !WIFSIGNALED(status));
+
+      step->complete();
+    }
+  }
+
   bool decodeMessage(const anna::DataBlock &message, anna::diameter::codec::Message &messageCodec) throw() {
 
     if (message.isEmpty())
@@ -150,14 +203,14 @@ throw() {
 
   // Begin
   std::string s_aux = a_beginTimestamp.asString();
-//  int deltaMs = (int)(a_beginTimestamp - a_testCase->getStartTimestamp());
-//  if (a_beginTimestamp != 0 && deltaMs > 0) s_aux += anna::functions::asString(" [%.3f]", deltaMs/1000.0);
+  //  int deltaMs = (int)(a_beginTimestamp - a_testCase->getStartTimestamp());
+  //  if (a_beginTimestamp != 0 && deltaMs > 0) s_aux += anna::functions::asString(" [%.3f]", deltaMs/1000.0);
   result->createAttribute("BeginTimestamp", s_aux);
 
   // End
   s_aux = a_endTimestamp.asString();
-//  deltaMs = (int)(a_endTimestamp - a_testCase->getStartTimestamp());
-//  if (a_endTimestamp != 0 && deltaMs > 0) s_aux += anna::functions::asString(" [%.3f]", deltaMs/1000.0);
+  //  deltaMs = (int)(a_endTimestamp - a_testCase->getStartTimestamp());
+  //  if (a_endTimestamp != 0 && deltaMs > 0) s_aux += anna::functions::asString(" [%.3f]", deltaMs/1000.0);
   result->createAttribute("EndTimestamp", s_aux);
 
   return result;
@@ -450,6 +503,7 @@ bool TestStepDelay::do_execute() throw() {
 void TestStepDelay::do_complete() throw() {
   a_timer = NULL;
   next(); // next() invoked here because execute() is always false for delay and never advance the iterator
+  // TODO, avoid this recursion
 }
 
 void TestStepDelay::do_reset() throw() {
@@ -554,9 +608,15 @@ throw() {
 
   result->createAttribute("Script", (a_script != "") ? a_script:"<no script>");
   if (a_errorMsg != "") result->createAttribute("ErrorMessage", a_errorMsg);
-  if (!a_threadRunning && a_resultCode != -2) {
-    result->createAttribute("ResultCode", a_resultCode);
-    //if (a_output != "") result->createAttribute("Output", a_output);
+  if (a_threadRunning) {
+    if (a_childPid != -1)
+      result->createAttribute("ChildPid", a_childPid);
+  }
+  else {
+    if (a_resultCode != -2) {
+      result->createAttribute("ResultCode", a_resultCode);
+      //if (a_output != "") result->createAttribute("Output", a_output);
+    }
   }
 
   return result;
@@ -575,11 +635,13 @@ bool TestStepCmd::do_execute() throw() {
       cmd.replace(index, strlen(SH_COMMAND_TAG_FOR_REPLACE__TESTSTEP_ID), anna::functions::asString(getNumber()));
 
     a_thread = std::thread(cmdRunOnThread, this, cmd);
+    //a_thread = std::thread(cmdRunOnThreadWithFork, this, cmd);
+
     a_thread.detach();
   }
 
   return false; // don't go next (wait complete): If system function on thread stucks, then the reset test case will stuck here forever.
-                // We must implement a interrupt procedure for the thread on reset call... TODO !      
+  // We must implement a interrupt procedure for the thread on reset call... TODO !
 }
 
 void TestStepCmd::do_complete() throw() {
@@ -597,17 +659,25 @@ void TestStepCmd::do_complete() throw() {
     a_testCase->setState(TestCase::State::Failed);
   else
     next(); // next() invoked here because execute() is always false for delay and never advance the iterator
+  // TODO, avoid this recursion
 }
 
 void TestStepCmd::do_reset() throw() {
 
-  if (a_threadRunning) {
-    std::string s_warn = anna::functions::asString("Thread still in progress: deprecating step %d for Test Case %llu", getNumber(), a_testCase->getId());
-    LOGWARNING(anna::Logger::warning(s_warn, ANNA_FILE_LOCATION));
-    a_threadDeprecated = true;
-  }
+    if (a_threadRunning) {
+      std::string s_warn = anna::functions::asString("Thread still in progress: deprecating step %d for Test Case %llu", getNumber(), a_testCase->getId());
+      LOGWARNING(anna::Logger::warning(s_warn, ANNA_FILE_LOCATION));
+      a_threadDeprecated = true;
+    }
+//  if (a_threadRunning) {
+//    std::string s_warn = anna::functions::asString("Thread still in progress: killing child pid %d within step %d for Test Case %llu", a_childPid, getNumber(), a_testCase->getId());
+//    LOGWARNING(anna::Logger::warning(s_warn, ANNA_FILE_LOCATION));
+//    kill (a_childPid, SIGKILL);
+//  }
 
   a_resultCode = -2;
+  a_errorMsg = "";
   //a_output = "";
+  a_childPid = -1;
 }
 
index 4f7e6e8..d239f97 100644 (file)
@@ -231,8 +231,10 @@ class TestStepCmd : public TestStep {
   std::string a_errorMsg;
   //std::string a_output; // for POPEN
 
+  pid_t a_childPid;
+
   public:
-    TestStepCmd(TestCase *testCase) : TestStep(testCase), a_threadRunning(false), a_threadDeprecated(false), a_resultCode(-2)/*, a_output("")*/, a_errorMsg("") { a_type = Type::Cmd; }
+    TestStepCmd(TestCase *testCase) : TestStep(testCase), a_threadRunning(false), a_threadDeprecated(false), a_resultCode(-2)/*, a_output("")*/, a_errorMsg(""), a_childPid(-1) { a_type = Type::Cmd; }
 
     // setter & getters
     void setThreadRunning(bool running) throw() { a_threadRunning = running; }
@@ -243,6 +245,8 @@ class TestStepCmd : public TestStep {
     const std::string &getErrorMsg() const throw() { return a_errorMsg; }
     //void appendOutput(const std::string &output) throw() { a_output += output; }
     //const std::string &getOutput() const throw() { return a_output; }
+    void setChildPid(pid_t pid) throw() { a_childPid = pid; }
+    const pid_t &getChildPid() const throw() { return a_childPid; }
 
     void setScript(const std::string &script) throw() { a_script = script; }
     const std::string &getScript() const throw() { return a_script; }