Allow to clear an specific test case
authorEduardo Ramos Testillano (ert) <eduardo.ramos.testillano@gmail.com>
Mon, 22 Nov 2021 21:57:05 +0000 (22:57 +0100)
committerEduardo Ramos Testillano (ert) <eduardo.ramos.testillano@gmail.com>
Mon, 22 Nov 2021 21:57:05 +0000 (22:57 +0100)
CMakeLists.txt
example/diameter/launcher/EventOperation.cpp
example/diameter/launcher/EventOperation.hpp
example/diameter/launcher/MyHandler.cpp
example/diameter/launcher/resources/HELP.md
include/anna/testing/TestCase.hpp
include/anna/testing/TestManager.hpp
source/testing/TestCase.cpp
source/testing/TestManager.cpp

index fd3d498..ad56e32 100644 (file)
@@ -12,7 +12,7 @@ enable_language(C CXX)
 # Project version
 set(VERSION_MAJOR 1)
 set(VERSION_MINOR 0)
-set(VERSION_PATCH 3)
+set(VERSION_PATCH 4)
 
 # Dynamic libraries not linked to build tree:
 set(CMAKE_SKIP_RPATH TRUE)
index 2b42486..8b45e61 100644 (file)
@@ -1105,12 +1105,23 @@ bool EventOperation::test__finished(std::string &response) {
   return true; // OK
 }
 
-bool EventOperation::test__clear(std::string &response) {
+bool EventOperation::test__clear(std::string &response, int id) {
 
   Launcher& my_app = static_cast <Launcher&>(anna::app::functions::getApp());
   anna::testing::TestManager &testManager = anna::testing::TestManager::instantiate();
 
-  return testManager.clearPool(response);
+  if (id == -1) {
+     return testManager.clearPool(response);
+  }
+
+  if (!testManager.findTestCase(id)) {
+      response += "cannot found test id (";
+      response += anna::functions::asString(id);
+      response += ")";
+      return false;
+  }
+
+  return testManager.clearTestCase(response, id);
 }
 
 bool EventOperation::test__junit(std::string &response, const std::string & targetFile) {
index dd54020..c88cb3c 100644 (file)
@@ -110,7 +110,7 @@ public:
   bool test__auto_reset(std::string &response, bool soft_hard);
   bool test__initialized(std::string &response);
   bool test__finished(std::string &response);
-  bool test__clear(std::string &response);
+  bool test__clear(std::string &response, int id = -1 /* all */);
   bool test__junit(std::string &response, const std::string & targetFile);
   bool test__summary_counts(std::string &response);
   bool test__summary_states(std::string &response);
index dfc29bd..1a7fdc5 100644 (file)
@@ -490,7 +490,9 @@ bool MyHandler::doPOST(const std::string &uri, const nlohmann::json &j, std::str
     result = eop.test__finished(response);
   }
   else if (opType == "/test-clear") {
-    result = eop.test__clear(response);
+    auto it = j.find("id");
+    int id = (it != j.end() && it->is_number_integer()) ? it->get<int>() : -1; // default is: all
+    result = eop.test__clear(response, id);
   }
   else if (opType == "/test-junit") {
     auto it = j.find("targetFile");
index 8429ef4..7a50b52 100644 (file)
@@ -1793,7 +1793,13 @@ Makes interactive a specific test case id. The amount of 0, implies no execution
 
 #### POST /test-clear
 
-**Request body**: none
+**Request body**:
+
+```
+{
+     ["id":[test identifier (integer: all by default (-1))]]
+}
+```
 
 **Response body**:
 
index 6eab8df..d17a9f8 100644 (file)
@@ -42,7 +42,7 @@ namespace testing {
 class TestCase {
 
   void assertInitialized() const noexcept(false);
-  void assertMessage(const anna::DataBlock &db, bool toEntity) noexcept(false);
+  std::string assertMessage(const anna::DataBlock &db, bool toEntity) noexcept(false);
 
 public:
 
@@ -124,6 +124,7 @@ public:
 
   // getters
   const unsigned int &getId() const { return a_id; }
+  const std::string &getKey() const { return a_key; }
   const std::string &getDescription() const { return a_description; }
 
   // setters
@@ -145,6 +146,7 @@ public:
 private:
   // private members:
   unsigned int a_id;
+  std::string a_key;
   std::string a_description;
   std::vector<TestStep*> a_steps;
   std::vector<TestStep*>::const_iterator a_stepsIt;
index a6b0c21..4b2fd23 100644 (file)
@@ -158,6 +158,7 @@ class TestManager : public anna::timex::TimeEventObserver, public anna::Singleto
     //  through the time manager. The first call to this method will start the time trigger system and check for new test cases to be launched.
     bool configureTTPS(int testTicksPerSecond) ;
 
+    bool clearTestCase(std::string &result, unsigned int id) ;
     bool clearPool(std::string &result) ;
     bool resetPool(bool hard /* hard reset includes in-progress test cases */) ;
     void setPoolRepeats(int repeats) { a_poolRepeats = repeats; }
index 991a254..c357e93 100644 (file)
@@ -73,6 +73,7 @@ std::string TestCase::DebugSummary::asString() const {
 
 TestCase::TestCase(unsigned int id, const std::string &description) :
     a_id(id),
+    a_key(""),
     a_description((description != "") ? description : (anna::functions::asString("Testcase_%d", id))),
     a_state(State::Initialized),
     a_startTimestamp(0),
@@ -107,6 +108,7 @@ anna::xml::Node* TestCase::asXML(anna::xml::Node* parent) const
   anna::xml::Node* result = parent->createChild("TestCase");
 
   result->createAttribute("Id", a_id);
+  if (a_key != "") result->createAttribute("Key", a_key);
   result->createAttribute("Description", a_description);
   result->createAttribute("State", asText(a_state));
   result->createAttribute("StartTimestamp", a_startTimestamp.asString());
@@ -311,7 +313,9 @@ void TestCase::assertInitialized() const noexcept(false) {
     throw anna::RuntimeException(anna::functions::asString("Cannot program anymore. The test case %llu (%s) has finished. You must reset it to append new steps (or do it during execution, which is also allowed).", a_id, a_description.c_str()), ANNA_FILE_LOCATION);
 }
 
-void TestCase::assertMessage(const anna::DataBlock &db, bool toEntity) noexcept(false) {
+std::string TestCase::assertMessage(const anna::DataBlock &db, bool toEntity) noexcept(false) {
+
+  std::string key;
 
   bool isRequest = anna::diameter::codec::functions::isRequest(db);
   bool registerKeys = ((isRequest && toEntity) || (!isRequest && !toEntity) /* (*) */);
@@ -330,16 +334,19 @@ void TestCase::assertMessage(const anna::DataBlock &db, bool toEntity) noexcept(
 
   if (registerKeys) {
     TestManager &testManager = TestManager::instantiate();
-    testManager.registerKey1(anna::diameter::helpers::base::functions::getSessionId(db), this);
+    key = anna::diameter::helpers::base::functions::getSessionId(db);
+    testManager.registerKey1(key, 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);
+    key = anna::diameter::helpers::dcca::functions::getSubscriptionIdData(db, anna::diameter::helpers::dcca::AVPVALUES__Subscription_Id_Type::END_USER_E164);
+    if (key == "") // try with IMSI
+      key = anna::diameter::helpers::dcca::functions::getSubscriptionIdData(db, anna::diameter::helpers::dcca::AVPVALUES__Subscription_Id_Type::END_USER_IMSI);
 
-    if (subscriberId != "")
-      testManager.registerKey2(subscriberId, this);
+    if (key != "")
+      testManager.registerKey2(key, this);
   }
+
+  return key;
 }
 
 void TestCase::addTimeout(const anna::Millisecond &timeout) noexcept(false) {
@@ -351,7 +358,7 @@ void TestCase::addTimeout(const anna::Millisecond &timeout) noexcept(false) {
 
 void TestCase::addSendDiameterXml2e(const anna::DataBlock &db, anna::diameter::comm::OriginHost *host, int stepNumber) noexcept(false) {
   assertInitialized();
-  assertMessage(db, true /* to entity */);
+  a_key = assertMessage(db, true /* to entity */);
 
   if (stepNumber != -1) {
     const TestStep *stepReferred = getStep(stepNumber);
@@ -376,7 +383,7 @@ void TestCase::addSendDiameterXml2e(const anna::DataBlock &db, anna::diameter::c
 
 void TestCase::addSendDiameterXml2c(const anna::DataBlock &db, anna::diameter::comm::OriginHost *host, int stepNumber) noexcept(false) {
   assertInitialized();
-  assertMessage(db, false /* to client */);
+  a_key = assertMessage(db, false /* to client */);
 
   if (stepNumber != -1) {
     const TestStep *stepReferred = getStep(stepNumber);
index e90d20d..b83f8d4 100644 (file)
@@ -299,6 +299,36 @@ TestCase *TestManager::getTestCase(unsigned int id, const std::string &descripti
   return result;
 }
 
+bool TestManager::clearTestCase(std::string &result, unsigned int id) {
+  result = "";
+
+  if (!tests()) {
+    result = "There are not programmed test cases to be removed";
+    return false;
+  }
+
+  test_pool_it it = ((id != -1) ? a_testPool.find(id) : a_currentTestIt);
+  if (it == a_testPool.end()) {
+    result = "Test case id provided not found";
+    return false;
+  }
+
+  if (!it->second->safeToClear()) {
+    result = "Test case id provided has running-thread steps. Check for stuck external procedures or try later.";
+    return false;
+  }
+
+  a_testPool.erase(it);
+
+  auto key1_it = a_key1TestCaseMap.find(it->second->getKey());
+  if (key1_it != a_key1TestCaseMap.end()) a_key1TestCaseMap.erase(key1_it);
+  auto key2_it = a_key2TestCaseMap.find(it->second->getKey());
+  if (key2_it != a_key2TestCaseMap.end()) a_key2TestCaseMap.erase(key2_it);
+
+  result = "Provided test case has been dropped";
+  return true;
+}
+
 bool TestManager::clearPool(std::string &result) {
 
   result = "";