Modified the clear operation. Now is 'conditional', so, when is unsafe,
it will be ignored. A message on http interface advice about trying
later because some running threads could be ongoing (check test
summary to confirm). Sometimes, it could be due to stuck external
procedures. The user is responsible to kill those stuck procedures
or guarantee they are timedout (it is recommended to wrap procedures
into safe containers (subshells) if you don't trust too much those
procedures).
Normally, step commands are not so usual. ADML FSM (finite state
machine) is better used through REST API from other controllers
with their own FSM and interface endpoints (no need for ADML
dedicated command-step threads).
// Reset test case and underlaying information (steps context)
bool reset(bool hard /* hard reset includes in-progress test cases */) throw();
// Reset test case and underlaying information (steps context)
bool reset(bool hard /* hard reset includes in-progress test cases */) throw();
+ // Check for clear (destroy steps)
+ bool safeToClear(); // false if something pending (running threads steps)
+
// getters
const unsigned int &getId() const throw() { return a_id; }
const std::string &getDescription() const throw() { return a_description; }
// getters
const unsigned int &getId() const throw() { return a_id; }
const std::string &getDescription() const throw() { return a_description; }
// 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) throw();
// 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) throw();
- bool clearPool() throw();
+ bool clearPool(std::string &result) throw();
bool resetPool(bool hard /* hard reset includes in-progress test cases */) throw();
void setPoolRepeats(int repeats) throw() { a_poolRepeats = repeats; }
int getPoolRepeats() const throw() { return a_poolRepeats; }
bool resetPool(bool hard /* hard reset includes in-progress test cases */) throw();
void setPoolRepeats(int repeats) throw() { a_poolRepeats = repeats; }
int getPoolRepeats() const throw() { return a_poolRepeats; }
#include <string>
#include <vector>
#include <thread>
#include <string>
#include <vector>
#include <thread>
// Project
#include <anna/core/DataBlock.hpp>
// Project
#include <anna/core/DataBlock.hpp>
public:
TestStepTimeout(TestCase *testCase) : TestStep(testCase), a_timeout(0), a_timer(NULL) { a_type = Type::Timeout; }
public:
TestStepTimeout(TestCase *testCase) : TestStep(testCase), a_timeout(0), a_timer(NULL) { a_type = Type::Timeout; }
+ ~TestStepTimeout() { do_reset(); }
// setter & getters
void setTimeout(const anna::Millisecond &t) throw() { a_timeout = t; }
// setter & getters
void setTimeout(const anna::Millisecond &t) throw() { a_timeout = t; }
a_expired(false),
a_originHost(NULL),
a_waitForRequestStepNumber(-1) {;}
a_expired(false),
a_originHost(NULL),
a_waitForRequestStepNumber(-1) {;}
- ~TestStepSendDiameterXml() {;}
+ ~TestStepSendDiameterXml() { do_reset(); }
// setter & getters
void setOriginHost(anna::diameter::comm::OriginHost *host) throw() { a_originHost = host; }
// setter & getters
void setOriginHost(anna::diameter::comm::OriginHost *host) throw() { a_originHost = host; }
public:
TestStepDelay(TestCase *testCase) : TestStep(testCase), a_delay(0), a_timer(NULL) { a_type = Type::Delay; }
public:
TestStepDelay(TestCase *testCase) : TestStep(testCase), a_delay(0), a_timer(NULL) { a_type = Type::Delay; }
+ ~TestStepDelay() { do_reset(); }
// setter & getters
void setDelay(const anna::Millisecond &d) throw() { a_delay = d; }
// setter & getters
void setDelay(const anna::Millisecond &d) throw() { a_delay = d; }
a_clientSession = NULL;
a_serverSession = NULL;
}
a_clientSession = NULL;
a_serverSession = NULL;
}
- ~TestStepWaitDiameter() {;}
+ ~TestStepWaitDiameter() { do_reset(); }
// setter & getters
void setCondition(bool fromEntity,
// setter & getters
void setCondition(bool fromEntity,
std::string a_script;
std::thread a_thread;
std::string a_script;
std::thread a_thread;
+ std::atomic<bool> a_threadRunning;
bool a_threadDeprecated;
int a_resultCode;
std::string a_errorMsg;
bool a_threadDeprecated;
int a_resultCode;
std::string a_errorMsg;
public:
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; }
public:
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; }
+ ~TestStepCmd() { do_reset(); }
- void setThreadRunning(bool running) throw() { a_threadRunning = running; }
+ void setThreadRunning() throw() { a_threadRunning = true; }
+ void setThreadNotRunning() throw() { a_threadRunning = false; }
+ bool threadRunning() const throw() { return a_threadRunning; }
+ bool threadNotRunning() const throw() { return !a_threadRunning; }
void setResultCode(int rc) throw() { a_resultCode = rc; }
int getResultCode() const throw() { return a_resultCode; }
void setResultCode(int rc) throw() { a_resultCode = rc; }
int getResultCode() const throw() { return a_resultCode; }
public:
TestStepIpLimit(TestCase *testCase) : TestStep(testCase), a_ipLimit(1) { a_type = Type::IpLimit; }
public:
TestStepIpLimit(TestCase *testCase) : TestStep(testCase), a_ipLimit(1) { a_type = Type::IpLimit; }
+ ~TestStepIpLimit() { do_reset(); }
// setter & getters
void setIpLimit(unsigned int limit) throw() { a_ipLimit = limit; }
// setter & getters
void setIpLimit(unsigned int limit) throw() { a_ipLimit = limit; }
}
TestCase::~TestCase() {
}
TestCase::~TestCase() {
+ // TestCase should not be deleted until is safeToClear()
reset(true); // hard reset
std::vector<TestStep*>::const_iterator it;
for (it = a_steps.begin(); it != a_steps.end(); it++) delete (*it);
}
reset(true); // hard reset
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)
throw() {
static const char* text [] = { "Initialized", "InProgress", "Failed", "Success" };
const char* TestCase::asText(const State::_v state)
throw() {
static const char* text [] = { "Initialized", "InProgress", "Failed", "Success" };
+bool TestCase::safeToClear() {
+
+ // Check if any step is running (command steps):
+ std::vector<TestStep*>::const_iterator it;
+ for (it = a_steps.begin(); it != a_steps.end(); it++) {
+ if ((*it)->getType() == TestStep::Type::Cmd) {
+ const TestStepCmd *tscmd = static_cast<const TestStepCmd*>(*it);
+ if(tscmd->threadRunning())
+ return false;
+ }
+ }
+
+ return true;
+}
+
void TestCase::assertInitialized() const throw(anna::RuntimeException) {
if (isFinished())
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::assertInitialized() const throw(anna::RuntimeException) {
if (isFinished())
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);
-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
+bool TestManager::clearPool(std::string &result) throw() {
+
+ result = "";
+
+ if (!tests()) {
+ result = "there are not programmed test cases to be removed";
+ return false;
+ }
+
+ int total = a_testPool.size();
+ int unsafe = 0;
+
+ test_pool_it it;
+ for (it = a_testPool.begin(); it != a_testPool.end(); it++) {
+ if (!it->second->safeToClear()) { // Check that non pending threads are running (command steps):
+ unsafe++;
+ }
+ }
+
+ if (unsafe > 0) {
+ result = "some test cases cannot be removed (";
+ result += anna::functions::asString(unsafe);
+ result += "/";
+ result += anna::functions::asString(total);
+ result += "), mainly those having running-thread steps. Check for stuck external procedures or try later.";
+ return false;
+ }
+
+ // Here is safe to clear:
+ for (it = a_testPool.begin(); it != a_testPool.end(); it++) {
+ delete it->second;
+ }
a_testPool.clear();
a_key1TestCaseMap.clear();
a_testPool.clear();
a_key1TestCaseMap.clear();
a_poolCycle = 1;
configureTTPS(0); // stop
a_statSummary.clear();
a_poolCycle = 1;
configureTTPS(0); // stop
a_statSummary.clear();
if (a_clock) {
result->createAttribute("AsynchronousSendings", a_synchronousAmount);
int ticksPerSecond = (a_synchronousAmount * 1000) / a_clock->getTimeout();
if (a_clock) {
result->createAttribute("AsynchronousSendings", a_synchronousAmount);
int ticksPerSecond = (a_synchronousAmount * 1000) / a_clock->getTimeout();
- result->createAttribute("TicksPerSecond", ticksPerSecond);
+ result->createAttribute("TicksPerSecond", a_clock->isActive() ? ticksPerSecond : 0);
}
if (a_currentTestIt != a_testPool.end()) {
result->createAttribute("CurrentTestCaseId", (*a_currentTestIt).first);
}
if (a_currentTestIt != a_testPool.end()) {
result->createAttribute("CurrentTestCaseId", (*a_currentTestIt).first);
void cmdRunOnThread (TestStepCmd *step, const std::string &cmd) {
void cmdRunOnThread (TestStepCmd *step, const std::string &cmd) {
- // Thread running:
- step->setThreadRunning(true);
+ // Thread running (will be set to false at complete()):
+ step->setThreadRunning();
std::cout << "Executed Command Test Step (" << a_script << ") [rc=" << a_resultCode << "]" << std::endl;
}
std::cout << "Executed Command Test Step (" << a_script << ") [rc=" << a_resultCode << "]" << std::endl;
}
- a_threadRunning = false;
if (a_threadDeprecated) {
a_threadDeprecated = false;
do_reset();
if (a_threadDeprecated) {
a_threadDeprecated = false;
do_reset();