Dynamic lib selection and deployment
[anna.git] / example / diameter / launcher / testing / TestCase.cpp
index 63851f7..087e29b 100644 (file)
@@ -11,7 +11,6 @@
 #include <fstream>
 #include <sstream>
 #include <cmath>
-
 #include <iostream>
 
 // Project
@@ -29,6 +28,7 @@
 #include <TestManager.hpp>
 
 
+///////////////////////////////////////////////////////////////////////////////////////////////////
 void TestCase::DebugSummary::addHint(const std::string &hint) throw() {
   event_t event;
   event.Timestamp = anna::functions::millisecond();
@@ -52,7 +52,19 @@ 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
@@ -114,8 +126,14 @@ 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;
+    if ((getState() == State::Failed) && (!testManager.getDumpFailedReports())) return;
+    if ((getState() == State::Success) && (!testManager.getDumpSuccessReports())) return;
     // report file name: cycle-<cycle id>.testcase-<test case id>.xml
 
     // FORMAT: We tabulate the cycle and test case in order to ease ordering of files by mean ls:
@@ -141,14 +159,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() {
@@ -161,7 +171,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;
   }
@@ -213,16 +223,18 @@ bool TestCase::reset(bool hard) throw() {
 }
 
 void TestCase::assertInitialized() const throw(anna::RuntimeException) {
-  if (a_state != State::Initialized)
-    throw anna::RuntimeException(anna::functions::asString("Cannot program anymore. The test case %llu was started. You must reset it to append new steps.", a_id), ANNA_FILE_LOCATION);
+  if (isFinished())
+    throw anna::RuntimeException(anna::functions::asString("Cannot program anymore. The test case %llu has finished. You must reset it to append new steps (or do it during execution, which is also allowed).", a_id), ANNA_FILE_LOCATION);
 }
 
 void TestCase::assertMessage(const anna::DataBlock &db, bool toEntity) throw(anna::RuntimeException) {
 
   bool isRequest = anna::diameter::codec::functions::isRequest(db);
-  bool registerSessionId = ((isRequest && toEntity) || (!isRequest && !toEntity) /* (*) */);
-  // (*) we register answers Session-Id assuming that we will know the Session-Id values created by the client (OCS)
-  // This is another solution for TODO(***) regarding diameter server testing. No tsure about the final implementation.
+  bool registerKeys = ((isRequest && toEntity) || (!isRequest && !toEntity) /* (*) */);
+  // (*) we register answers Session-Id "assuming" that we will know the Session-Id values created by the client.
+  // This is another solution regarding diameter server testing. No sure about the final implementation.
+  // We will help registering also subscriber data, because certain messages (i.e. SLR) coming from clients could
+  //  have specific Session-Id value (unknown at test programming), and normally are identified by subscriber.
 
   // Check hop-by-hop:
   if (isRequest) {
@@ -232,32 +244,40 @@ void TestCase::assertMessage(const anna::DataBlock &db, bool toEntity) throw(ann
     a_hopByHops[hbh] = NULL; // may be assigned to a wait condition
   }
 
-  if (registerSessionId)
-    TestManager::instantiate().registerSessionId(anna::diameter::helpers::base::functions::getSessionId(db), this);
+  if (registerKeys) {
+    TestManager &testManager = TestManager::instantiate();
+    testManager.registerSessionId(anna::diameter::helpers::base::functions::getSessionId(db), this);
+
+
+    std::string subscriberId = anna::diameter::helpers::dcca::functions::getSubscriptionIdData(db, anna::diameter::helpers::dcca::AVPVALUES__Subscription_Id_Type::END_USER_E164);
+    if (subscriberId == "") // try with IMSI
+      subscriberId = anna::diameter::helpers::dcca::functions::getSubscriptionIdData(db, anna::diameter::helpers::dcca::AVPVALUES__Subscription_Id_Type::END_USER_IMSI);
+
+    if (subscriberId != "")
+      testManager.registerSubscriberId(subscriberId, this);
+  }
 }
 
 void TestCase::addTimeout(const anna::Millisecond &timeout) throw(anna::RuntimeException) {
   assertInitialized();
   TestStepTimeout *step = new TestStepTimeout(this);
   step->setTimeout(timeout);
-  a_steps.push_back(step);
+  addStep(step);
 }
 
-void TestCase::addSendxml2e(const anna::DataBlock &db, RealmNode *realm, int stepNumber) throw(anna::RuntimeException) {
+void TestCase::addSendxml2e(const anna::DataBlock &db, OriginHost *host, int stepNumber) throw(anna::RuntimeException) {
   assertInitialized();
   assertMessage(db, true /* to entity */);
 
   if (stepNumber != -1) {
-    int steps = a_steps.size();
-    int stepIndx = stepNumber - 1;
-    if ((stepIndx < 0) || (stepIndx > (a_steps.size()-1)))
-      throw anna::RuntimeException(anna::functions::asString("Step number (%d) out of range (test case %llu)", stepNumber, a_id), ANNA_FILE_LOCATION);
+    const TestStep *stepReferred = getStep(stepNumber);
+    if (!stepReferred)
+      throw anna::RuntimeException(anna::functions::asString("Step number (%d) do not exists (test case %llu)", stepNumber, a_id), ANNA_FILE_LOCATION);
 
-    TestStep *stepReferred = a_steps[stepIndx];
     if (stepReferred->getType() != TestStep::Type::Wait)
       throw anna::RuntimeException(anna::functions::asString("Step number (%d) must refer to a 'wait' step (test case %llu)", stepNumber, a_id), ANNA_FILE_LOCATION);
 
-    const TestCondition &tc = (static_cast<TestStepWait*>(stepReferred))->getCondition();
+    const TestCondition &tc = (static_cast<const TestStepWait*>(stepReferred))->getCondition();
     if (tc.getCode() == "0") { // if regexp used, is not possible to detect this kind of errors
       throw anna::RuntimeException(anna::functions::asString("Step number (%d) must refer to a 'wait for request' step (test case %llu)", stepNumber, a_id), ANNA_FILE_LOCATION);
     }
@@ -265,26 +285,26 @@ void TestCase::addSendxml2e(const anna::DataBlock &db, RealmNode *realm, int ste
 
   TestStepSendxml2e *step = new TestStepSendxml2e(this);
   step->setMsgDataBlock(db);
-  step->setRealmNode(realm);
+  step->setOriginHost(host);
   step->setWaitForRequestStepNumber(stepNumber); // -1 means, no reference
-  a_steps.push_back(step);
+  addStep(step);
 }
 
-void TestCase::addSendxml2c(const anna::DataBlock &db, RealmNode *realm, int stepNumber) throw(anna::RuntimeException) {
+void TestCase::addSendxml2c(const anna::DataBlock &db, OriginHost *host, int stepNumber) throw(anna::RuntimeException) {
   assertInitialized();
   assertMessage(db, false /* to client */);
 
   TestStepSendxml2c *step = new TestStepSendxml2c(this);
   step->setMsgDataBlock(db);
-  step->setRealmNode(realm);
-  a_steps.push_back(step);
+  step->setOriginHost(host);
+  addStep(step);
 }
 
 void TestCase::addDelay(const anna::Millisecond &delay) throw(anna::RuntimeException) {
   assertInitialized();
   TestStepDelay *step = new TestStepDelay(this);
   step->setDelay(delay);
-  a_steps.push_back(step);
+  addStep(step);
 }
 
 void TestCase::addWait(bool fromEntity,
@@ -305,20 +325,19 @@ void TestCase::addWait(bool fromEntity,
   else {
     if (hopByHop != "") {
       if (hopByHop[0] == '#') {
-        int steps = a_steps.size();
-        if (steps == 0)
+        if (steps() == 0)
           throw anna::RuntimeException(anna::functions::asString("No steps has been programmed, step reference is nonsense (test case %llu)", a_id), ANNA_FILE_LOCATION);
 
         int stepNumber = atoi(hopByHop.substr(1).c_str());
-        int stepIndx = stepNumber - 1;
-        if ((stepIndx < 0) || (stepIndx > (steps-1)))
-          throw anna::RuntimeException(anna::functions::asString("Step reference number %d out of range [1-%d]", stepNumber, steps), ANNA_FILE_LOCATION);
 
-        TestStep *stepReferred = a_steps[stepIndx];
+        const TestStep *stepReferred = getStep(stepNumber);
+        if (!stepReferred)
+          throw anna::RuntimeException(anna::functions::asString("Step reference number (%d) do not exists (test case %llu)", stepNumber, a_id), ANNA_FILE_LOCATION);
+
         if (stepReferred->getType() != TestStep::Type::Sendxml2e && stepReferred->getType() != TestStep::Type::Sendxml2c)
           throw anna::RuntimeException(anna::functions::asString("Step number must refer to a 'sendxml2e' or 'sendxml2c' step (test case %llu)", a_id), ANNA_FILE_LOCATION);
 
-        const anna::DataBlock &db = (static_cast<TestStepSendxml*>(stepReferred))->getMsgDataBlock();
+        const anna::DataBlock &db = (static_cast<const TestStepSendxml*>(stepReferred))->getMsgDataBlock();
         bool isAnswer = anna::diameter::codec::functions::isAnswer(db);
         if (isAnswer)
           throw anna::RuntimeException(anna::functions::asString("Step number must refer to a request message (test case %llu)", a_id), ANNA_FILE_LOCATION);
@@ -335,12 +354,12 @@ void TestCase::addWait(bool fromEntity,
   if (!step) step = new TestStepWait(this);
   step->setCondition(fromEntity, code, bitR, usedHopByHop, applicationId, sessionId, resultCode, msisdn, imsi, serviceContextId);
 
-  LOGWARNING(
+  LOGINFORMATION(
     if (hasSameCondition(step->getCondition()))
-      anna::Logger::warning(anna::functions::asString("The same wait condition has already been programmed in this test case (%llu). Are you sure ?", a_id), ANNA_FILE_LOCATION);
+      anna::Logger::information(anna::functions::asString("The same wait condition has already been programmed in this test case (%llu). Are you sure ?", a_id), ANNA_FILE_LOCATION);
   );
 
-  a_steps.push_back(step);
+  addStep(step);
 }
 
 void TestCase::addWaitRegexp(bool fromEntity, const std::string &regexp) throw(anna::RuntimeException) {
@@ -349,12 +368,12 @@ void TestCase::addWaitRegexp(bool fromEntity, const std::string &regexp) throw(a
   TestStepWait *step = new TestStepWait(this);
   step->setCondition(fromEntity, regexp);
 
-  LOGWARNING(
+  LOGINFORMATION(
     if (hasSameCondition(step->getCondition()))
-      anna::Logger::warning(anna::functions::asString("The same wait condition has already been programmed in this test case (%llu). Are you sure ?", a_id), ANNA_FILE_LOCATION);
+      anna::Logger::information(anna::functions::asString("The same wait condition has already been programmed in this test case (%llu). Are you sure ?", a_id), ANNA_FILE_LOCATION);
   );
 
-  a_steps.push_back(step);
+  addStep(step);
 }
 
 void TestCase::addCommand(const std::string &cmd) throw(anna::RuntimeException) {
@@ -363,7 +382,7 @@ void TestCase::addCommand(const std::string &cmd) throw(anna::RuntimeException)
   TestStepCmd *step = new TestStepCmd(this);
   step->setScript(cmd);
 
-  a_steps.push_back(step);
+  addStep(step);
 }
 
 TestStepWait *TestCase::searchNextWaitConditionFulfilled(const anna::DataBlock &message, bool waitFromEntity) throw() {
@@ -381,8 +400,7 @@ TestStepWait *TestCase::searchNextWaitConditionFulfilled(const anna::DataBlock &
 }
 
 const TestStep *TestCase::getStep(int stepNumber) const throw() {
-  int stepIndx = stepNumber - 1;
-  if ((stepIndx < 0) || (stepIndx > (a_steps.size()-1))) return NULL;
-  std::vector<TestStep*>::const_iterator it = (a_steps.begin() + stepNumber);
-  return (*it);
+  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];
 }