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";
// 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)
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)
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;
}
#include <fstream>
#include <sstream>
#include <cmath>
-#include <iterator>
-#include <vector>
#include <iostream>
// Project
#include <TestManager.hpp>
+///////////////////////////////////////////////////////////////////////////////////////////////////
void TestCase::DebugSummary::addHint(const std::string &hint) throw() {
event_t event;
event.Timestamp = anna::functions::millisecond();
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)
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);
}
}
}
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;
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
out.close();
}
}
-
- // Count in-progress test cases:
- if (inProgress()) {
- testManager.setInProgressCountDelta(1);
- }
- else if (previousState == State::InProgress){
- testManager.setInProgressCountDelta(-1);
- }
}
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;
}
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;
// 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;
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;
}
}
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];
}
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 }; };
//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),
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;
// 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;
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();
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);
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 {
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);
);
}
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();
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
}
}
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.
}
}
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
}
}
}
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
// Process
#include <TestTimer.hpp>
+#include <TestCase.hpp>
namespace anna {
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;
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
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&);
void cancelTimer(TestTimer*) throw();
void release(anna::timex::TimeEvent*) throw();
+
public:
void registerSessionId(const std::string &sessionId, const TestCase *testCase) throw(anna::RuntimeException);
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)
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