X-Git-Url: https://git.teslayout.com/public/public/public/?a=blobdiff_plain;f=source%2Ftesting%2FTestStep.cpp;h=a6d8185c16514a57a80ef3b0df01aa7ec9f24b3c;hb=5a6cba5fde2b2f538a7515f8293cc0a8d9589dfa;hp=e1804371dd184db18094071ec7d56e7c93fb74d4;hpb=9fa68da11c56250017da9735e4a5dd3fd3b2021b;p=anna.git diff --git a/source/testing/TestStep.cpp b/source/testing/TestStep.cpp index e180437..a6d8185 100644 --- a/source/testing/TestStep.cpp +++ b/source/testing/TestStep.cpp @@ -15,6 +15,7 @@ #include // perror #include // exit #include // waitpid, pid_t, WNOHANG +#include // cmd with fork: #include @@ -55,8 +56,8 @@ namespace { void cmdRunOnThread (TestStepCmd *step, const std::string &cmd) { - // Thread running: - step->setThreadRunning(true); + // Thread running (will be set to false at complete()): + step->setThreadRunning(); int status = -2; @@ -65,6 +66,7 @@ namespace { sigemptyset(&sa.sa_mask); sa.sa_flags = SA_RESTART | SA_NOCLDSTOP; if (sigaction(SIGCHLD, &sa, 0) != -1) { + status = system(cmd.c_str()); /* POPEN version: char readbuf[256]; @@ -101,6 +103,7 @@ namespace { // TODO: mutex the step while setting data here !! } +/* void cmdRunOnThreadWithFork (TestStepCmd *step, const std::string &cmd) { // Thread running: @@ -148,8 +151,9 @@ namespace { step->complete(); } } +*/ - bool decodeMessage(const anna::DataBlock &message, anna::diameter::codec::Message &messageCodec) throw() { + bool decodeMessage(const anna::DataBlock &message, anna::diameter::codec::Message &messageCodec) { if (message.isEmpty()) return false; @@ -181,7 +185,7 @@ void TestStep::initialize(TestCase *testCase) { a_number = testCase->steps() + 1; // testCase is not NULL } -bool TestStep::decodeMessage(bool trust) throw() { +bool TestStep::decodeMessage(bool trust) { if (a_messageCodec) return true; a_messageCodec = new anna::diameter::codec::Message; if (::decodeMessage(a_message, *a_messageCodec)) return true; @@ -196,13 +200,13 @@ bool TestStep::decodeMessage(bool trust) throw() { } const char* TestStep::asText(const Type::_v type) -throw() { - static const char* text [] = { "Unconfigured", "Timeout", "Sendxml2e", "Sendxml2c", "Delay", "Wait", "Command" }; +{ + static const char* text [] = { "Unconfigured", "Timeout", "SendDiameterXmlToEntity", "SendDiameterXmlToClient", "Delay", "Wait", "Command", "IpLimit" }; return text [type]; } anna::xml::Node* TestStep::asXML(anna::xml::Node* parent) -throw() { +{ anna::xml::Node* result = parent->createChild("TestStep"); result->createAttribute("Number", a_number); @@ -221,15 +225,18 @@ throw() { // if (a_endTimestamp != 0 && deltaMs > 0) s_aux += anna::functions::asString(" [%.3f]", deltaMs/1000.0); result->createAttribute("EndTimestamp", s_aux); + if (a_beginTimestamp != 0 && a_endTimestamp != 0) + result->createAttribute("LapseMilliseconds", getLapseMs()); + return result; } -std::string TestStep::asXMLString() throw() { +std::string TestStep::asXMLString() { anna::xml::Node root("root"); return anna::xml::Compiler().apply(asXML(&root)); } -bool TestStep::execute() throw() { +bool TestStep::execute() { int ia = a_testCase->interactiveAmount(); if (ia > -1) { @@ -239,21 +246,47 @@ bool TestStep::execute() throw() { if (a_executed) return false; // avoid repeating (this implies amount consumption) } - LOGDEBUG(anna::Logger::debug(anna::functions::asString("EXECUTING %s (step number %d) for Test Case %llu (%p)", asText(a_type), a_number, a_testCase->getId(), this), ANNA_FILE_LOCATION)); + const char *literal = "Execute %s Test Step %d/%d (test case %llu)"; + + TestManager& testManager (TestManager::instantiate ()); + if (testManager.getDumpStdout()) { + bool dump = (a_type == Type::Wait) ? (!a_completed) : true; + if (dump) { + std::cout << std::endl << "=> " << anna::functions::asString(literal, asText(a_type), a_number, a_testCase->steps(), a_testCase->getId()) << std::endl; + } + } + + LOGDEBUG(anna::Logger::debug(anna::functions::asString(literal, asText(a_type), a_number, a_testCase->steps(), a_testCase->getId()), ANNA_FILE_LOCATION)); setBeginTimestamp(anna::functions::millisecond()); a_executed = true; return do_execute(); } -void TestStep::complete() throw() { - LOGDEBUG(anna::Logger::debug(anna::functions::asString("COMPLETE %s (step number %d) for Test Case %llu (%p)", asText(a_type), a_number, a_testCase->getId(), this), ANNA_FILE_LOCATION)); +void TestStep::complete() { + + const char *literal = "Complete %s Test Step %d/%d (test case %llu)"; + + TestManager& testManager (TestManager::instantiate ()); + if (testManager.getDumpStdout()) { + std::cout << "=> " << anna::functions::asString(literal, asText(a_type), a_number, a_testCase->steps(), a_testCase->getId()) << std::endl; + } + + LOGDEBUG(anna::Logger::debug(anna::functions::asString(literal, asText(a_type), a_number, a_testCase->steps(), a_testCase->getId()), ANNA_FILE_LOCATION)); a_completed = true; setEndTimestamp(anna::functions::millisecond()); do_complete(); } -void TestStep::reset() throw() { - LOGDEBUG(anna::Logger::debug(anna::functions::asString("RESET %s (step number %d) for Test Case %llu (%p)", asText(a_type), a_number, a_testCase->getId(), this), ANNA_FILE_LOCATION)); +void TestStep::reset() { + + const char *literal = "Reset %s Test Step %d/%d (test case %llu)"; + + TestManager& testManager (TestManager::instantiate ()); + if (testManager.getDumpStdout()) { + std::cout << "=> " << anna::functions::asString(literal, asText(a_type), a_number, a_testCase->steps(), a_testCase->getId()) << std::endl; + } + + LOGDEBUG(anna::Logger::debug(anna::functions::asString(literal, asText(a_type), a_number, a_testCase->steps(), a_testCase->getId()), ANNA_FILE_LOCATION)); // type and testCase kept a_completed = false; a_executed = false; @@ -262,7 +295,7 @@ void TestStep::reset() throw() { do_reset(); } -void TestStep::next() throw() { +void TestStep::next() { a_testCase->nextStep(); a_testCase->process(); } @@ -272,7 +305,7 @@ void TestStep::next() throw() { // TestStepTimeout //////////////////////////////////////////////////////////////////////////////////////////////////////// anna::xml::Node* TestStepTimeout::asXML(anna::xml::Node* parent) -throw() { +{ anna::xml::Node* result = TestStep::asXML(parent); // end timestamp will be 0 if test finished OK //parent->createChild("TestStepTimeout"); result->createAttribute("Timeout", a_timeout.asString()); @@ -280,7 +313,7 @@ throw() { return result; } -bool TestStepTimeout::do_execute() throw() { +bool TestStepTimeout::do_execute() { try { a_timer = TestManager::instantiate().createTimer((TestCaseStep*)this, a_timeout, TestTimer::Type::TimeLeft); } @@ -293,21 +326,28 @@ bool TestStepTimeout::do_execute() throw() { return true; // go next } -void TestStepTimeout::do_complete() throw() { +void TestStepTimeout::do_complete() { int stepNumber = getNumber(); if (stepNumber == a_testCase->steps()) { a_testCase->addDebugSummaryHint(anna::functions::asString("Timeout expired (step number %d) but it was the last test case step", stepNumber)); // before report (when set Failed state) a_testCase->setState(TestCase::State::Success); + if (TestManager::instantiate().getDumpStdout()) { + std::cout << "Expired Timeout Test LAST Step: considered SUCCESSFUL TEST CASE" << std::endl; + } } else if (a_testCase->getState() == TestCase::State::InProgress) { // sure a_testCase->addDebugSummaryHint(anna::functions::asString("Timeout expired (step number %d) before test case finished", stepNumber)); // before report (when set Failed state) a_testCase->setState(TestCase::State::Failed); + if (TestManager::instantiate().getDumpStdout()) { + std::cout << "Expired Timeout Test Step: FAILED TEST CASE" << std::endl; + } } a_timer = NULL; } -void TestStepTimeout::do_reset() throw() { +void TestStepTimeout::cancelTimer() { + if (!a_timer) return; try { TestManager::instantiate().cancelTimer(a_timer); } @@ -318,19 +358,23 @@ void TestStepTimeout::do_reset() throw() { //a_timeout = 0; THIS IS CONFIGURATION INFO } +void TestStepTimeout::do_reset() { + cancelTimer(); +} + //////////////////////////////////////////////////////////////////////////////////////////////////////// -// TestStepSendxml +// TestStepSendDiameterXml //////////////////////////////////////////////////////////////////////////////////////////////////////// -anna::xml::Node* TestStepSendxml::asXML(anna::xml::Node* parent) -throw() { +anna::xml::Node* TestStepSendDiameterXml::asXML(anna::xml::Node* parent) +{ anna::xml::Node* result = TestStep::asXML(parent); - //parent->createChild("TestStepSendxml"); + //parent->createChild("TestStepSendDiameterXml"); std::string msg = "", xmlmsg = ""; // Message if (TestManager::instantiate().getDumpHex()) { if (a_message.isEmpty()) { - msg = ""; + msg = "[empty]"; } else { msg = "\n"; msg += a_message.asString(); msg += "\n"; @@ -343,7 +387,7 @@ throw() { xmlmsg += "\n"; } else { - xmlmsg = ""; + xmlmsg = "[unable to decode, check traces]"; } if (msg != "") result->createAttribute("Message", msg); @@ -355,23 +399,27 @@ throw() { return result; } -bool TestStepSendxml::do_execute() throw() { +bool TestStepSendDiameterXml::do_execute() { bool success = false; - std::string failReason; + std::string failReason = "Error sending diameter message"; anna::diameter::comm::Entity *entity = a_originHost->getEntity(); // by default anna::diameter::comm::LocalServer *localServer = a_originHost->getDiameterServer(); // by default - const TestStepWait *tsw = NULL; + const TestStepWaitDiameter *tsw = NULL; anna::diameter::comm::Message *msg = a_originHost->createCommMessage(); try { if (a_waitForRequestStepNumber != -1) { + bool thisIsAnswer = anna::diameter::codec::functions::isAnswer(getMsgDataBlock()); + LOGDEBUG( + std::string trace = anna::functions::asString("'Wait For Request' step number for this %s: %d", (thisIsAnswer ? "answer":"request"), a_waitForRequestStepNumber); + anna::Logger::debug(trace, ANNA_FILE_LOCATION); + ); // Referenced request in the 'wait for request step': - tsw = static_cast(a_testCase->getStep(a_waitForRequestStepNumber)); + tsw = static_cast(a_testCase->getStep(a_waitForRequestStepNumber)); const anna::DataBlock &referenceRequest = tsw->getMsgDataBlock(); std::string sessionIdReferenceRequest = anna::diameter::helpers::base::functions::getSessionId(referenceRequest); - bool thisIsAnswer = anna::diameter::codec::functions::isRequest(getMsgDataBlock()); if (thisIsAnswer) { // is an answer: try to copy sequence information; alert about Session-Id discrepance anna::diameter::HopByHop hbh = anna::diameter::codec::functions::getHopByHop(referenceRequest); @@ -430,7 +478,7 @@ bool TestStepSendxml::do_execute() throw() { // Detailed log: if(a_originHost->logEnabled()) { if (decodeMessage(true /* trust */)) { - std::string detail = usedClientSession ? usedClientSession->asString() : ""; // shouldn't happen + std::string detail = usedClientSession ? usedClientSession->asString() : "[null client session]"; // shouldn't happen a_originHost->writeLogFile(*a_messageCodec, (success ? "sent2e" : "send2eError"), detail); } } @@ -464,7 +512,7 @@ bool TestStepSendxml::do_execute() throw() { // Detailed log: if(a_originHost->logEnabled()) { if (decodeMessage(true /* trust */)) { - std::string detail = usedServerSession ? usedServerSession->asString() : ""; // shouldn't happen + std::string detail = usedServerSession ? usedServerSession->asString() : "[null server session]"; // shouldn't happen a_originHost->writeLogFile(*a_messageCodec, (success ? "sent2c" : "send2cError"), detail); } } @@ -485,10 +533,14 @@ bool TestStepSendxml::do_execute() throw() { complete(); } + if (TestManager::instantiate().getDumpStdout()) { + std::cout << "Executed SendDiameterXml Test Step: " << (success ? "OK":"ERROR") << std::endl; + } + return success; // go next if sent was OK } -void TestStepSendxml::do_reset() throw() { +void TestStepSendDiameterXml::do_reset() { a_expired = false; //a_message.clear(); //a_messageAlreadyDecoded = false; @@ -498,7 +550,7 @@ void TestStepSendxml::do_reset() throw() { // TestStepDelay //////////////////////////////////////////////////////////////////////////////////////////////////////// anna::xml::Node* TestStepDelay::asXML(anna::xml::Node* parent) -throw() { +{ anna::xml::Node* result = TestStep::asXML(parent); //parent->createChild("TestStepDelay"); @@ -507,7 +559,7 @@ throw() { return result; } -bool TestStepDelay::do_execute() throw() { +bool TestStepDelay::do_execute() { if (a_delay == 0) { complete(); return true; } // special case try { a_timer = TestManager::instantiate().createTimer((TestCaseStep*)this, a_delay, TestTimer::Type::Delay); @@ -521,14 +573,18 @@ bool TestStepDelay::do_execute() throw() { return false; // don't go next (wait complete) } -void TestStepDelay::do_complete() throw() { +void TestStepDelay::do_complete() { if (a_delay == 0) return; // special case a_timer = NULL; + if (TestManager::instantiate().getDumpStdout()) { + std::cout << "Consumed Delay Test Step (" << a_delay << " milliseconds)" << std::endl; + } 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() { +void TestStepDelay::cancelTimer() { + if (!a_timer) return; if (a_delay == 0) return; // special case try { TestManager::instantiate().cancelTimer(a_timer); @@ -540,13 +596,18 @@ void TestStepDelay::do_reset() throw() { //a_delay = 0; THIS IS CONFIGURATION INFO } +void TestStepDelay::do_reset() { + cancelTimer(); +} + + //////////////////////////////////////////////////////////////////////////////////////////////////////// -// TestStepWait +// TestStepWaitDiameter //////////////////////////////////////////////////////////////////////////////////////////////////////// -void TestStepWait::setCondition(bool fromEntity, +void TestStepWaitDiameter::setCondition(bool fromEntity, const std::string &code, const std::string &bitR, const std::string &hopByHop, const std::string &applicationId, const std::string &sessionId, const std::string &resultCode, - const std::string &msisdn, const std::string &imsi, const std::string &serviceContextId) throw() { + const std::string &msisdn, const std::string &imsi, const std::string &serviceContextId) { a_condition.setReceivedFromEntity(fromEntity); a_condition.setCode(code); @@ -559,20 +620,20 @@ void TestStepWait::setCondition(bool fromEntity, a_condition.setServiceContextId(serviceContextId); } -void TestStepWait::setConditionRegexpHex(bool fromEntity, const std::string ®exp) throw() { +void TestStepWaitDiameter::setConditionRegexpHex(bool fromEntity, const std::string ®exp) { a_condition.setReceivedFromEntity(fromEntity); a_condition.setRegexpHex(regexp); } -void TestStepWait::setConditionRegexpXml(bool fromEntity, const std::string ®exp) throw() { +void TestStepWaitDiameter::setConditionRegexpXml(bool fromEntity, const std::string ®exp) { a_condition.setReceivedFromEntity(fromEntity); a_condition.setRegexpXml(regexp); } -anna::xml::Node* TestStepWait::asXML(anna::xml::Node* parent) -throw() { +anna::xml::Node* TestStepWaitDiameter::asXML(anna::xml::Node* parent) +{ anna::xml::Node* result = TestStep::asXML(parent); - //parent->createChild("TestStepWait"); + //parent->createChild("TestStepWaitDiameter"); std::string msg = "", xmlmsg = ""; // Condition @@ -581,7 +642,7 @@ throw() { // Message if (TestManager::instantiate().getDumpHex()) { if (a_message.isEmpty()) { - msg = ""; + msg = "[empty]"; } else { msg = "\n"; msg += a_message.asString(); msg += "\n"; @@ -589,7 +650,7 @@ throw() { } if (a_message.isEmpty()) { - xmlmsg = ""; + xmlmsg = "[empty]"; } else { if (decodeMessage()) { @@ -598,7 +659,7 @@ throw() { xmlmsg += "\n"; } else { - xmlmsg = ""; + xmlmsg = "[unable to decode, check traces]"; } } @@ -610,26 +671,35 @@ throw() { return result; } -bool TestStepWait::do_execute() throw() { +bool TestStepWaitDiameter::do_execute() { return a_completed; } -void TestStepWait::do_complete() throw() { +void TestStepWaitDiameter::do_complete() { //a_testCase->process(); // next() not invoked; we only want to reactivate the test case // avoid stack overflow: we will process the test case externally when incoming message is fulfilled (TestCase.cpp), and TestManager is noticed } -bool TestStepWait::fulfilled(const anna::DataBlock &db/*, bool matchSessionId*/) throw() { +bool TestStepWaitDiameter::fulfilled(const anna::DataBlock &db/*, bool matchSessionId*/) { if (a_condition.comply(db/*, matchSessionId*/)) { a_message = db; // store matched complete(); + + if (TestManager::instantiate().getDumpStdout()) { + std::cout << "Fulfilled Wait diameter Test Step" << std::endl; + } + return true; } + if (TestManager::instantiate().getDumpStdout()) { + std::cout << "NOT Fulfilled Wait diameter Test Step" << std::endl; + } + return false; } -void TestStepWait::do_reset() throw() { +void TestStepWaitDiameter::do_reset() { a_message.clear(); a_clientSession = NULL; a_serverSession = NULL; @@ -639,11 +709,11 @@ void TestStepWait::do_reset() throw() { // TestStepCmd //////////////////////////////////////////////////////////////////////////////////////////////////////// anna::xml::Node* TestStepCmd::asXML(anna::xml::Node* parent) -throw() { +{ anna::xml::Node* result = TestStep::asXML(parent); //parent->createChild("TestStepCmd"); - result->createAttribute("Script", (a_script != "") ? a_script:""); + result->createAttribute("Script", (a_script != "") ? a_script:"[no script]"); if (a_errorMsg != "") result->createAttribute("ErrorMessage", a_errorMsg); if (a_threadRunning) { if (a_childPid != -1) @@ -659,7 +729,7 @@ throw() { return result; } -bool TestStepCmd::do_execute() throw() { +bool TestStepCmd::do_execute() { if (!a_threadRunning /* || a_threadDeprecated DO NOT WANT TO OVERLAP ... */) { // Special tags to replace: std::string cmd = getScript(); @@ -681,9 +751,13 @@ bool TestStepCmd::do_execute() throw() { // We must implement a interrupt procedure for the thread on reset call... TODO ! } -void TestStepCmd::do_complete() throw() { +void TestStepCmd::do_complete() { + + if (TestManager::instantiate().getDumpStdout()) { + std::cout << "Executed Command Test Step (" << a_script << ") [rc=" << a_resultCode << "]" << std::endl; + } - a_threadRunning = false; + setThreadNotRunning(); if (a_threadDeprecated) { a_threadDeprecated = false; do_reset(); @@ -699,7 +773,7 @@ void TestStepCmd::do_complete() throw() { // TODO, avoid this recursion } -void TestStepCmd::do_reset() throw() { +void TestStepCmd::do_reset() { 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()); @@ -718,3 +792,25 @@ void TestStepCmd::do_reset() throw() { a_childPid = -1; } +anna::xml::Node* TestStepIpLimit::asXML(anna::xml::Node* parent) +{ + anna::xml::Node* result = TestStep::asXML(parent); + std::string limit = (a_ipLimit != UINT_MAX) ? anna::functions::asString(a_ipLimit) : "[no limit]"; + result->createAttribute("IpLimit", limit); + + return result; +} + +bool TestStepIpLimit::do_execute() { + TestManager::instantiate().setInProgressLimit(a_ipLimit); + complete(); + return true; // go next +} + +void TestStepIpLimit::do_complete() { + if (TestManager::instantiate().getDumpStdout()) { + std::string limit = (a_ipLimit != UINT_MAX) ? anna::functions::asString(a_ipLimit) : "[no limit]"; + std::cout << "Executed IpLimit Test Step (value = " << limit << ")" << std::endl; + } +} +