Basic stat summary for testcases
authorEduardo Ramos Testillano <eduardo.ramos.testillano@ericsson.com>
Tue, 6 Oct 2015 15:57:37 +0000 (17:57 +0200)
committerEduardo Ramos Testillano <eduardo.ramos.testillano@ericsson.com>
Tue, 6 Oct 2015 16:27:01 +0000 (18:27 +0200)
example/diameter/launcher/Launcher.cpp
example/diameter/launcher/testing/TestCase.cpp
example/diameter/launcher/testing/TestCase.hpp
example/diameter/launcher/testing/TestManager.cpp
example/diameter/launcher/testing/TestManager.hpp

index edeaf88..e8ac212 100644 (file)
@@ -1354,7 +1354,9 @@ std::string Launcher::help() const throw() {
   result += "\n";
   result += "\n   test|clear                    Clears all the programmed test cases and stop testing (if in progress).";
   result += "\n";
-  result += "\n   test|stat                     Global statistics.";
+  result += "\n   test|summary                  Test manager general report (number of test cases, counts by state, global configuration,";
+  result += "\n                                 forced in-progress limitation, reports visibility, etc.). Be careful when you have reports";
+  result += "\n                                 dumps enabled because all the programmed test cases will be dump and that could be heavy.";
   result += "\n";
   result += "\n";
   result += "\nUSING OPERATIONS INTERFACE";
@@ -1747,6 +1749,8 @@ void Launcher::eventOperation(const std::string &operation, std::string &respons
     // test|interact|amount|id            Makes interactive a specific test case id. The amount is the margin of execution steps ...
     // test|reset|<soft/hard>[|id]        Reset the test case for id provided, all the tests when missing ...
     // test|clear                         Clears all the programmed test cases.
+    // test|summary                       Test manager general report (number of test cases, counts by state ...
+
 
     if(param1 == "ttps") {
       if (numParams > 2)
@@ -1916,6 +1920,10 @@ void Launcher::eventOperation(const std::string &operation, std::string &respons
         opt_response_content = "there are not programmed test cases to be removed";
       }
     }
+    else if(param1 == "summary") {
+      response_content = testManager.asXMLString();
+      return;
+    }
     else {
       int id = atoi(param1.c_str());
       if(id < 0)
@@ -2119,7 +2127,7 @@ throw() {
   anna::statistics::Engine::instantiate().asXML(result);
 
   // Testing: could be heavy if test case reports are enabled
-  //TestManager::instantiate().asXML(result);
+  TestManager::instantiate().asXML(result);
 
   return result;
 }
index e95a670..3d91f32 100644 (file)
@@ -11,8 +11,6 @@
 #include <fstream>
 #include <sstream>
 #include <cmath>
-#include <iterator>
-#include <vector>
 #include <iostream>
 
 // Project
@@ -30,6 +28,7 @@
 #include <TestManager.hpp>
 
 
+///////////////////////////////////////////////////////////////////////////////////////////////////
 void TestCase::DebugSummary::addHint(const std::string &hint) throw() {
   event_t event;
   event.Timestamp = anna::functions::millisecond();
@@ -53,12 +52,24 @@ anna::xml::Node* TestCase::DebugSummary::asXML(anna::xml::Node* parent) const th
 
   return result;
 };
+///////////////////////////////////////////////////////////////////////////////////////////////////
 
 
+TestCase::TestCase(unsigned int id) :
+    a_id(id),
+    a_state(State::Initialized),
+    a_startTime(0),
+    a_interactiveAmount(-1) {
+
+  /*a_stepsIt = a_steps.end()*/;
+  TestManager &testManager = TestManager::instantiate();
+  testManager.tcsStateStats(State::Initialized, State::Initialized);
+}
+
 TestCase::~TestCase() {
   reset(true); // hard reset
-  std::map<int/* step number*/, TestStep*>::const_iterator it;
-  for (it = a_steps.begin(); it != a_steps.end(); it++) delete (it->second);
+  std::vector<TestStep*>::const_iterator it;
+  for (it = a_steps.begin(); it != a_steps.end(); it++) delete (*it);
 }
 
 const char* TestCase::asText(const State::_v state)
@@ -77,9 +88,9 @@ throw() {
   int steps = a_steps.size();
   if (steps != 0) {
     result->createAttribute("NumberOfTestSteps", steps);
-    std::map<int/* step number*/, TestStep*>::const_iterator it;
+    std::vector<TestStep*>::const_iterator it;
     for (it = a_steps.begin(); it != a_steps.end(); it++) {
-      it->second->asXML(result);
+      (*it)->asXML(result);
     }
   }
 
@@ -98,11 +109,11 @@ std::string TestCase::asXMLString() const throw() {
 }
 
 bool TestCase::hasSameCondition(const TestCondition &condition) const throw() {
-  std::map<int/* step number*/, TestStep*>::const_iterator it;
+  std::vector<TestStep*>::const_iterator it;
   TestStepWait *step;
   for (it = a_steps.begin(); it != a_steps.end(); it++) {
-    if (it->second->getType() != TestStep::Type::Wait) continue;
-    step = (TestStepWait *)(it->second);
+    if ((*it)->getType() != TestStep::Type::Wait) continue;
+    step = (TestStepWait *)(*it);
     if (step->getCondition() == condition) return true;
   }
   return false;
@@ -115,6 +126,11 @@ void TestCase::setState(const State::_v &state) throw() {
   if (state == previousState) return;
   a_state = state;
   TestManager &testManager = TestManager::instantiate();
+
+  // stats:
+  testManager.tcsStateStats(previousState, state);
+
+
   if (isFinished()) {
     if (!testManager.getDumpReports()) return;
     // report file name: cycle-<cycle id>.testcase-<test case id>.xml
@@ -142,14 +158,6 @@ void TestCase::setState(const State::_v &state) throw() {
       out.close();
     }
   }
-
-  // Count in-progress test cases:
-  if (inProgress()) {
-    testManager.setInProgressCountDelta(1);
-  }
-  else if (previousState == State::InProgress){
-    testManager.setInProgressCountDelta(-1);
-  }
 }
 
 bool TestCase::done() throw() {
@@ -162,7 +170,7 @@ bool TestCase::done() throw() {
 }
 
 bool TestCase::process() throw() {
-  if (a_steps.size() == 0) {
+  if (steps() == 0) {
     LOGWARNING(anna::Logger::warning(anna::functions::asString("Test case %llu is empty, nothing to execute", a_id), ANNA_FILE_LOCATION));
     return false;
   }
@@ -183,7 +191,7 @@ bool TestCase::process() throw() {
   if (done()) return false;
 
   bool somethingDone = false;
-  while (a_stepsIt->second->execute()) { // executes returns 'true' if the next step must be also executed (execute until can't stand no more)
+  while ((*a_stepsIt)->execute()) { // executes returns 'true' if the next step must be also executed (execute until can't stand no more)
     nextStep();
     // Check end of the test case:
     if (done()) return false;
@@ -200,9 +208,9 @@ bool TestCase::reset(bool hard) throw() {
 
   // Clean stage ////////////////////////////
   // id is kept
-  std::map<int/* step number*/, TestStep*>::iterator it;
+  std::vector<TestStep*>::iterator it;
   for (it = a_steps.begin(); it != a_steps.end(); it++)
-    it->second->reset();
+    (*it)->reset();
 
   a_debugSummary.clear();
   a_startTime = 0;
@@ -367,10 +375,10 @@ void TestCase::addCommand(const std::string &cmd) throw(anna::RuntimeException)
 TestStepWait *TestCase::searchNextWaitConditionFulfilled(const anna::DataBlock &message, bool waitFromEntity) throw() {
 
   TestStepWait *result;
-  for (std::map<int/* step number*/, TestStep*>::const_iterator it = a_stepsIt /* current */; it != a_steps.end(); it++) {
-    if (it->second->getType() != TestStep::Type::Wait) continue;
-    if (it->second->isCompleted()) continue;
-    result = (TestStepWait*)(it->second);
+  for (std::vector<TestStep*>::const_iterator it = a_stepsIt /* current */; it != a_steps.end(); it++) {
+    if ((*it)->getType() != TestStep::Type::Wait) continue;
+    if ((*it)->isCompleted()) continue;
+    result = (TestStepWait*)(*it);
     if ((result->getCondition().receivedFromEntity() == waitFromEntity) && (result->fulfilled(message)))
       return result;
   }
@@ -379,7 +387,7 @@ TestStepWait *TestCase::searchNextWaitConditionFulfilled(const anna::DataBlock &
 }
 
 const TestStep *TestCase::getStep(int stepNumber) const throw() {
-  std::map<int/* step number*/, TestStep*>::const_iterator it = a_steps.find(stepNumber);
-  if (it != a_steps.end()) return it->second;
-  return NULL;
+  if (stepNumber < 1 || stepNumber > steps()) return NULL;
+//  return a_steps.at(stepNumber-1);  // http://stackoverflow.com/questions/3269809/stdvectorat-vs-operator-surprising-results-5-to-10-times-slower-f
+  return a_steps[stepNumber-1];
 }
index ab8e4a3..715856a 100644 (file)
@@ -57,7 +57,7 @@ public:
     anna::xml::Node* asXML(anna::xml::Node* parent) const throw();
   };
 
-  TestCase(unsigned int id) : a_id(id), a_state(State::Initialized), a_startTime(0), a_interactiveAmount(-1) { /*a_stepsIt = a_steps.end()*/;}
+  TestCase(unsigned int id);
   ~TestCase();
 
   struct State { enum _v { Initialized, InProgress, Failed, Success }; };
@@ -109,7 +109,7 @@ public:
 
   //helpers
   int steps() const throw() { return a_steps.size(); }
-  void addStep(TestStep *step) throw() { a_steps[1+steps()] = step; }
+  void addStep(TestStep *step) throw() { a_steps.push_back(step); }
 
   TestStepWait *searchNextWaitConditionFulfilled(const anna::DataBlock &message, bool waitFromEntity) throw();
       // When a message arrives, we identify the test case by mean the Session-Id. Then, from the current step iterator (included),
@@ -123,8 +123,8 @@ public:
 private:
   // private members:
   unsigned int a_id;
-  std::map<int/* step number*/, TestStep*> a_steps;
-  std::map<int/* step number*/, TestStep*>::const_iterator a_stepsIt;
+  std::vector<TestStep*> a_steps;
+  std::vector<TestStep*>::const_iterator a_stepsIt;
   std::map<anna::diameter::HopByHop, TestStep*> a_hopByHops; // for wait-answer
   State::_v a_state;
   anna::Millisecond a_startTime;
index 6dfec1e..ee6be63 100644 (file)
@@ -21,7 +21,6 @@
 
 // Process
 #include <TestManager.hpp>
-#include <TestCase.hpp>
 #include <TestClock.hpp>
 #include <Launcher.hpp>
 #include <RealmNode.hpp>
 class TestTimer;
 
 
+
+
+///////////////////////////////////////////////////////////////////////////////////////////////////
+void TestManager::StatSummary::newTCState(const TestCase::State::_v beginState, const TestCase::State::_v endState) throw() {
+
+  if ((beginState == TestCase::State::Initialized)&&(endState == TestCase::State::Initialized)) { // special case (new test case provisioning)
+    a_initializedTcs++;
+    return;
+  }
+
+  switch (beginState) {
+  case TestCase::State::Initialized: a_initializedTcs--; break;
+  case TestCase::State::InProgress: a_inprogressTcs--; break;
+  case TestCase::State::Failed: a_failedTcs--; break;
+  case TestCase::State::Success: a_sucessTcs--; break;
+  default: break;
+  }
+  switch (endState) {
+  case TestCase::State::Initialized: a_initializedTcs++; break;
+  case TestCase::State::InProgress: a_inprogressTcs++; break;
+  case TestCase::State::Failed: a_failedTcs++; break;
+  case TestCase::State::Success: a_sucessTcs++; break;
+  default: break;
+  }
+}
+
+void TestManager::StatSummary::clear() throw() {
+  a_initializedTcs = 0;
+  a_inprogressTcs = 0;
+  a_failedTcs = 0;
+  a_sucessTcs = 0;
+}
+
+anna::xml::Node *TestManager::StatSummary::asXML(anna::xml::Node* parent) const throw() {
+  anna::xml::Node* result = parent->createChild("StatSummary");
+
+  anna::xml::Node* tcs = result->createChild("TestCasesCounts");
+  tcs->createAttribute("Total", a_initializedTcs + a_inprogressTcs + a_failedTcs + a_sucessTcs);
+  tcs->createAttribute("Initialized", a_initializedTcs);
+  tcs->createAttribute("InProgress", a_inprogressTcs);
+  tcs->createAttribute("Failed", a_failedTcs);
+  tcs->createAttribute("Success", a_sucessTcs);
+
+  return result;
+}
+///////////////////////////////////////////////////////////////////////////////////////////////////
+
+
+
 TestManager::TestManager() :
-  anna::timex::TimeEventObserver("TestManager") {
+      anna::timex::TimeEventObserver("TestManager") {
   a_timeController = NULL;
   a_reportsDirectory = "./";
   a_dumpReports = false;
@@ -39,7 +87,6 @@ TestManager::TestManager() :
   a_synchronousAmount = 1;
   a_poolRepeats = 0; // repeat disabled by default
   a_poolCycle = 1;
-  a_inProgressCount = 0;
   a_inProgressLimit = UINT_MAX; // no limit
   a_clock = NULL;
   //a_testPool.clear();
@@ -76,9 +123,9 @@ throw(anna::RuntimeException) {
   result->setTimeout(timeout);
 
   LOGDEBUG(
-    std::string msg("TestManager::createTimer | ");
-    msg += result->asString();
-    anna::Logger::debug(msg, ANNA_FILE_LOCATION);
+      std::string msg("TestManager::createTimer | ");
+  msg += result->asString();
+  anna::Logger::debug(msg, ANNA_FILE_LOCATION);
   );
 
   a_timeController->activate(result);
@@ -91,9 +138,9 @@ throw() {
     return;
 
   LOGDEBUG(
-    std::string msg("TestManager::cancel | ");
-    msg += timer->asString();
-    anna::Logger::debug(msg, ANNA_FILE_LOCATION);
+      std::string msg("TestManager::cancel | ");
+  msg += timer->asString();
+  anna::Logger::debug(msg, ANNA_FILE_LOCATION);
   );
 
   try {
@@ -153,15 +200,15 @@ bool TestManager::configureTTPS(int testTicksPerSecond) throw() {
 
   if (a_synchronousAmount > 1) {
     LOGWARNING(
-      std::string msg = anna::functions::asString("Desired testing time trigger rate (%d events per second) requires more than one sending per event (%d every %lld milliseconds). Consider launch more instances with lower rate (for example %d ADML processes with %d ttps), or configure %d or more sockets to the remote endpoints to avoid burst sendings",
-                        testTicksPerSecond,
-                        a_synchronousAmount,
-                        admlTimeInterval.getValue(),
-                        a_synchronousAmount,
-                        1000/admlTimeInterval,
-                        a_synchronousAmount);
-
-      anna::Logger::warning(msg, ANNA_FILE_LOCATION);
+        std::string msg = anna::functions::asString("Desired testing time trigger rate (%d events per second) requires more than one sending per event (%d every %lld milliseconds). Consider launch more instances with lower rate (for example %d ADML processes with %d ttps), or configure %d or more sockets to the remote endpoints to avoid burst sendings",
+            testTicksPerSecond,
+            a_synchronousAmount,
+            admlTimeInterval.getValue(),
+            a_synchronousAmount,
+            1000/admlTimeInterval,
+            a_synchronousAmount);
+
+    anna::Logger::warning(msg, ANNA_FILE_LOCATION);
     );
   }
 
@@ -208,6 +255,8 @@ TestCase *TestManager::getTestCase(unsigned int id) throw() {
 bool TestManager::clearPool() throw() {
   if (!tests()) return false;
   for (test_pool_it it = a_testPool.begin(); it != a_testPool.end(); it++) delete it->second;
+  // TODO: stop the possible command threads or there will be a core dump
+
   a_testPool.clear();
   a_sessionIdTestCaseMap.clear();
   a_currentTestIt = a_testPool.end();
@@ -251,7 +300,7 @@ bool TestManager::nextTestCase() throw() {
   while (true) {
 
     // Limit for in-progress test cases:
-    if (a_inProgressCount >= a_inProgressLimit) {
+    if (getInProgressCount() >= a_inProgressLimit) {
       LOGDEBUG(anna::Logger::debug(anna::functions::asString("TestManager next case ignored (over in-progress count limit: %llu)", a_inProgressLimit), ANNA_FILE_LOCATION));
       return true; // wait next tick to release OTA test cases
     }
@@ -271,13 +320,13 @@ bool TestManager::nextTestCase() throw() {
       }
       else {
         LOGWARNING(
-          std::string nolimit = (a_poolRepeats != -1) ? "":" [no limit]";
-          anna::Logger::warning(anna::functions::asString("Testing pool cycle %d completed (repeats configured: %d%s). Restarting for the %s cycle", a_poolCycle, a_poolRepeats, nolimit.c_str(), (a_poolRepeats == a_poolCycle) ? "last":"next"), ANNA_FILE_LOCATION);
+            std::string nolimit = (a_poolRepeats != -1) ? "":" [no limit]";
+        anna::Logger::warning(anna::functions::asString("Testing pool cycle %d completed (repeats configured: %d%s). Restarting for the %s cycle", a_poolCycle, a_poolRepeats, nolimit.c_str(), (a_poolRepeats == a_poolCycle) ? "last":"next"), ANNA_FILE_LOCATION);
         );
         a_poolCycle++;
         //a_currentTestIt = a_testPool.begin();
         return true; // avoids infinite loop: if the cycle takes less time than test cases completion, below reset never will turns state
-                     // into Initialized and this while will be infinite. It is preferable to wait one tick when the cycle is completed.
+        // into Initialized and this while will be infinite. It is preferable to wait one tick when the cycle is completed.
       }
     }
 
@@ -289,8 +338,8 @@ bool TestManager::nextTestCase() throw() {
     if (a_currentTestIt->second->getState() != TestCase::State::InProgress) {
       a_currentTestIt->second->process();
       return true; // is not probably to reach still In-Progress test cases from previous cycles due to the whole
-                   //  time for complete the test cases pool regarding the single test case lifetime. You shouldn't
-                   //  forget to programm a test case timeout with a reasonable value
+      //  time for complete the test cases pool regarding the single test case lifetime. You shouldn't
+      //  forget to programm a test case timeout with a reasonable value
     }
   }
 }
@@ -401,7 +450,7 @@ throw() {
   if (a_poolRepeats) result->createAttribute("PoolRepeats", a_poolRepeats);
   else result->createAttribute("PoolRepeats", "disabled");
   result->createAttribute("PoolCycle", a_poolCycle);
-  result->createAttribute("InProgressCount", a_inProgressCount);
+  a_statSummary.asXML(result);
   if (a_inProgressLimit == UINT_MAX)
     result->createAttribute("InProgressLimit", "<no limit>");
   else
index 6a292e4..2f61501 100644 (file)
@@ -19,6 +19,7 @@
 
 // Process
 #include <TestTimer.hpp>
+#include <TestCase.hpp>
 
 
 namespace anna {
@@ -51,6 +52,24 @@ typedef std::map<unsigned int /* test case id */, TestCase*>::iterator test_pool
    Timer Manager for testing system
 */
 class TestManager : public anna::timex::TimeEventObserver, public anna::Singleton <TestManager> {
+
+  // Statistics summary:
+  class StatSummary {
+
+    unsigned int a_initializedTcs;
+    unsigned int a_inprogressTcs;
+    unsigned int a_failedTcs;
+    unsigned int a_sucessTcs;
+
+  public:
+    void newTCState(const TestCase::State::_v beginState, const TestCase::State::_v endState) throw();
+    void clear() throw();
+    unsigned int getInProgressCount() const throw() { return a_inprogressTcs; }
+    anna::xml::Node* asXML(anna::xml::Node* parent) const throw();
+  };
+
+
+
   typedef anna::Recycler <TestTimer> timer_container;
 
   anna::timex::Engine* a_timeController;
@@ -65,7 +84,6 @@ class TestManager : public anna::timex::TimeEventObserver, public anna::Singleto
   test_pool_it a_currentTestIt;
   int a_poolRepeats; // repeat pool N times
   int a_poolCycle; // current cycle, from 1 to N
-  unsigned int a_inProgressCount;
   unsigned int a_inProgressLimit; // limit load to have this value
 
   // Test clock
@@ -81,6 +99,8 @@ class TestManager : public anna::timex::TimeEventObserver, public anna::Singleto
   std::map<std::string /* session id's */, TestCase*> a_sessionIdTestCaseMap; // stores used Session-Id values within a test case.
                                                                               // No other can use them, but a test case could use more than one.
 
+  StatSummary a_statSummary; // general statistics
+
 
   TestManager();
   TestManager(const TestManager&);
@@ -89,6 +109,7 @@ class TestManager : public anna::timex::TimeEventObserver, public anna::Singleto
   void cancelTimer(TestTimer*) throw();
   void release(anna::timex::TimeEvent*) throw();
 
+
   public:
 
     void registerSessionId(const std::string &sessionId, const TestCase *testCase) throw(anna::RuntimeException);
@@ -115,8 +136,7 @@ class TestManager : public anna::timex::TimeEventObserver, public anna::Singleto
     int getPoolRepeats() const throw() { return a_poolRepeats; }
     int getPoolCycle() const throw() { return a_poolCycle; }
 
-    unsigned int getInProgressCount() const throw() { return a_inProgressCount; }
-    void setInProgressCountDelta(unsigned int delta) throw() { a_inProgressCount += delta; }
+    unsigned int getInProgressCount() const throw() { return a_statSummary.getInProgressCount(); }
     unsigned int getInProgressLimit() const throw() { return a_inProgressLimit; }
     void setInProgressLimit(unsigned int limit) throw() { a_inProgressLimit = limit; } // 0 = UINT_MAX (no limit)
 
@@ -132,6 +152,11 @@ class TestManager : public anna::timex::TimeEventObserver, public anna::Singleto
     anna::xml::Node* asXML(anna::xml::Node* parent) const throw();
     std::string asXMLString() const throw();
 
+    // stats
+    void tcsStateStats(const TestCase::State::_v beginState, const TestCase::State::_v endState) throw() {
+      a_statSummary.newTCState(beginState, endState);
+    }
+
 
   friend class anna::Singleton <TestManager>;
   friend class TestStepTimeout; // createTimer