From: Eduardo Ramos Testillano Date: Sun, 4 Oct 2015 17:47:30 +0000 (+0200) Subject: Fork variant for TestStep command X-Git-Tag: REFACTORING_TESTING_LIBRARY~103 X-Git-Url: https://git.teslayout.com/public/public/public/?p=anna.git;a=commitdiff_plain;h=603b76b5dc02acdfd87c58c51b6d48ae1858f58d Fork variant for TestStep command --- diff --git a/example/diameter/launcher/Launcher.cpp b/example/diameter/launcher/Launcher.cpp index eac8b26..ff86f46 100644 --- a/example/diameter/launcher/Launcher.cpp +++ b/example/diameter/launcher/Launcher.cpp @@ -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 ("; diff --git a/example/diameter/launcher/testing/TestManager.cpp b/example/diameter/launcher/testing/TestManager.cpp index 38916d0..6dfec1e 100644 --- a/example/diameter/launcher/testing/TestManager.cpp +++ b/example/diameter/launcher/testing/TestManager.cpp @@ -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; diff --git a/example/diameter/launcher/testing/TestStep.cpp b/example/diameter/launcher/testing/TestStep.cpp index c1f27d8..75ede74 100644 --- a/example/diameter/launcher/testing/TestStep.cpp +++ b/example/diameter/launcher/testing/TestStep.cpp @@ -16,6 +16,11 @@ #include // exit #include // waitpid, pid_t, WNOHANG +// cmd with fork: +#include +#include + + // Project #include #include @@ -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:""); 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; } diff --git a/example/diameter/launcher/testing/TestStep.hpp b/example/diameter/launcher/testing/TestStep.hpp index 4f7e6e8..d239f97 100644 --- a/example/diameter/launcher/testing/TestStep.hpp +++ b/example/diameter/launcher/testing/TestStep.hpp @@ -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; }