#include <anna/diameter/helpers/base/functions.hpp>
#include <anna/diameter/helpers/dcca/functions.hpp>
#include <anna/comm/functions.hpp>
+#include <anna/core/functions.hpp>
#include <anna/diameter.comm/ClientSession.hpp>
#include <anna/diameter.comm/ServerSession.hpp>
#include <anna/testing/TestStep.hpp>
///////////////////////////////////////////////////////////////////////////////////////////////////
-void TestManager::StatSummary::newTCState(const TestCase::State::_v beginState, const TestCase::State::_v endState) throw() {
+void TestManager::StatSummary::newTCState(const TestCase::State::_v beginState, const TestCase::State::_v endState) {
if ((beginState == TestCase::State::Initialized)&&(endState == TestCase::State::Initialized)) { // special case (new test case provisioning)
a_initializedTcs++;
}
}
-void TestManager::StatSummary::clear() throw() {
+void TestManager::StatSummary::clear() {
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 *TestManager::StatSummary::asXML(anna::xml::Node* parent) const {
anna::xml::Node* result = parent->createChild("StatSummary");
anna::xml::Node* tcs = result->createChild("TestCasesCounts");
a_dumpSuccessReports = false;
a_dumpHexMessages = false;
+ a_dumpStdout = false;
a_synchronousAmount = 1;
a_poolRepeats = 0; // repeat disabled by default
a_poolCycle = 1;
a_currentTestIt = a_testPool.end();
}
-void TestManager::registerKey1(const std::string &key, const TestCase *testCase) throw(anna::RuntimeException) {
+void TestManager::registerKey1(const std::string &key, const TestCase *testCase) noexcept(false) {
auto it = a_key1TestCaseMap.find(key);
if (it != a_key1TestCaseMap.end()) { // found
}
}
-void TestManager::registerKey2(const std::string &key, const TestCase *testCase) throw(anna::RuntimeException) {
+void TestManager::registerKey2(const std::string &key, const TestCase *testCase) noexcept(false) {
auto it = a_key2TestCaseMap.find(key);
if (it != a_key2TestCaseMap.end()) { // found
}
TestTimer* TestManager::createTimer(TestCaseStep* testCaseStep, const anna::Millisecond &timeout, const TestTimer::Type::_v type)
-throw(anna::RuntimeException) {
+noexcept(false) {
TestTimer* result(NULL);
if(a_timeController == NULL)
}
void TestManager::cancelTimer(TestTimer* timer)
-throw() {
+{
if(timer == NULL)
return;
// Se invoca automaticamente desde anna::timex::Engine
//------------------------------------------------------------------------------------------
void TestManager::release(anna::timex::TimeEvent* timeEvent)
-throw() {
+{
TestTimer* timer = static_cast <TestTimer*>(timeEvent);
timer->setContext(NULL);
a_timers.release(timer);
}
-bool TestManager::configureTTPS(int testTicksPerSecond) throw() {
+bool TestManager::configureTTPS(int testTicksPerSecond) {
- if (testTicksPerSecond == 0) {
+ if (testTicksPerSecond == 0) {
if (a_clock) {
a_timeController->cancel(a_clock);
LOGDEBUG(anna::Logger::debug("Testing timer clock stopped !", ANNA_FILE_LOCATION));
return true;
}
-bool TestManager::gotoTestCase(unsigned int id) throw() {
+bool TestManager::gotoTestCase(unsigned int id) {
test_pool_it it = a_testPool.find(id);
if (it != a_testPool.end()) {
a_currentTestIt = it;
return false;
}
-TestCase *TestManager::findTestCase(unsigned int id) const throw() { // id = -1 provides current test case triggered
+bool TestManager::runTestCase(unsigned int id) {
+ test_pool_it it = a_testPool.find(id);
+ if (it != a_testPool.end()) {
+ a_currentTestIt = it;
+
+ // execTestCases will get the next one, we must return 1 position:
+ if (a_currentTestIt == a_testPool.begin())
+ a_currentTestIt = a_testPool.end();
+ else
+ a_currentTestIt--;
+
+ return execTestCases(1);
+ }
+
+ return false;
+}
+
+TestCase *TestManager::findTestCase(unsigned int id) const { // id = -1 provides current test case triggered
if (!tests()) return NULL;
test_pool_it it = ((id != -1) ? a_testPool.find(id) : a_currentTestIt);
return NULL;
}
-TestCase *TestManager::getTestCase(unsigned int id) throw() {
+TestCase *TestManager::getTestCase(unsigned int id, const std::string &description) {
test_pool_nc_it it = a_testPool.find(id);
if (it != a_testPool.end()) return it->second;
- TestCase *result = new TestCase(id);
+ TestCase *result = new TestCase(id, description);
a_testPool[id] = result;
return result;
}
-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) {
+
+ 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_poolCycle = 1;
configureTTPS(0); // stop
a_statSummary.clear();
+
+ result = "all the programmed test cases have been dropped";
return true;
}
-bool TestManager::resetPool(bool hard) throw() {
+bool TestManager::resetPool(bool hard) {
bool result = false; // any reset
if (!tests()) return result;
return result;
}
-bool TestManager::tick() throw() {
+bool TestManager::tick() {
LOGDEBUG(anna::Logger::debug("New test clock tick !", ANNA_FILE_LOCATION));
return execTestCases(a_synchronousAmount);
}
-bool TestManager::execTestCases(int sync_amount) throw() {
+bool TestManager::execTestCases(int sync_amount) {
if (!tests()) {
LOGWARNING(anna::Logger::warning("Testing pool is empty. You need programming", ANNA_FILE_LOCATION));
return true;
}
-bool TestManager::nextTestCase() throw() {
+bool TestManager::nextTestCase() {
while (true) {
}
}
-TestCase *TestManager::getDiameterTestCaseFromSessionId(const anna::DataBlock &message, std::string &sessionId) throw() {
+TestCase *TestManager::getDiameterTestCaseFromSessionId(const anna::DataBlock &message, std::string &sessionId) {
try {
sessionId = anna::diameter::helpers::base::functions::getSessionId(message);
}
return NULL;
}
-TestCase *TestManager::getDiameterTestCaseFromSubscriberId(const anna::DataBlock &message, std::string &subscriberId) throw() {
+TestCase *TestManager::getDiameterTestCaseFromSubscriberId(const anna::DataBlock &message, std::string &subscriberId) {
try {
subscriberId = anna::diameter::helpers::dcca::functions::getSubscriptionIdData(message, anna::diameter::helpers::dcca::AVPVALUES__Subscription_Id_Type::END_USER_E164);
if (subscriberId == "") // try with IMSI
return NULL;
}
-void TestManager::receiveDiameterMessage(const anna::DataBlock &message, const anna::diameter::comm::ClientSession *clientSession) throw(anna::RuntimeException) {
+void TestManager::receiveDiameterMessage(const anna::DataBlock &message, const anna::diameter::comm::ClientSession *clientSession) noexcept(false) {
// Testing disabled:
if (!tests()) return;
}
// Work with Test case:
- TestStepWait *tsw = tc->searchNextWaitConditionFulfilled(message, true /* comes from entity */);
+ TestStepWaitDiameter *tsw = tc->searchNextWaitConditionFulfilled(message, true /* comes from entity */);
if (!tsw) { // store as 'uncovered'
std::string hint = "Uncovered condition for received message from entity over Session-Id '"; hint += sessionId; hint += "'; ";
}
}
-void TestManager::receiveDiameterMessage(const anna::DataBlock &message, const anna::diameter::comm::ServerSession *serverSession) throw(anna::RuntimeException) {
+void TestManager::receiveDiameterMessage(const anna::DataBlock &message, const anna::diameter::comm::ServerSession *serverSession) noexcept(false) {
// Testing disabled:
if (!tests()) return;
}
// Work with Test case:
- TestStepWait *tsw = tc->searchNextWaitConditionFulfilled(message, false /* comes from client */);
+ TestStepWaitDiameter *tsw = tc->searchNextWaitConditionFulfilled(message, false /* comes from client */);
if (!tsw) { // store as 'uncovered'
std::string hint = "Uncovered condition for received message from client over Session-Id '"; hint += sessionId; hint += "'; ";
}
anna::xml::Node* TestManager::asXML(anna::xml::Node* parent) const
-throw() {
+{
anna::xml::Node* result = parent->createChild("TestManager");
int poolSize = a_testPool.size();
result->createAttribute("PoolCycle", a_poolCycle);
a_statSummary.asXML(result);
if (a_inProgressLimit == UINT_MAX)
- result->createAttribute("InProgressLimit", "<no limit>");
+ result->createAttribute("InProgressLimit", "[no limit]");
else
result->createAttribute("InProgressLimit", a_inProgressLimit);
result->createAttribute("DumpInitializedReports", (a_dumpInitializedReports ? "yes":"no"));
result->createAttribute("DumpFailedReports", (a_dumpFailedReports ? "yes":"no"));
result->createAttribute("DumpSuccessReports", (a_dumpSuccessReports ? "yes":"no"));
result->createAttribute("DumpHexMessages", (a_dumpHexMessages ? "yes":"no"));
+ result->createAttribute("DumpStdout", (a_dumpStdout ? "yes":"no"));
result->createAttribute("AutoResetHard", (a_autoResetHard ? "yes":"no"));
result->createAttribute("ReportsDirectory", a_reportsDirectory);
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);
return result;
}
-std::string TestManager::asXMLString() const throw() {
+anna::xml::Node* TestManager::junitAsXML(anna::xml::Node* parent) const
+{
+ // if only a single testsuite element is present, the testsuites element can be omitted
+ //anna::xml::Node* result = parent->createChild("testsuites");
+ anna::xml::Node* result = parent->createChild("testsuite");
+
+/*
+https://stackoverflow.com/questions/4922867/what-is-the-junit-xml-format-specification-that-hudson-supports
+
+JUnit XSD file
+==============
+https://windyroad.com.au/dl/Open%20Source/JUnit.xsd
+
+EXAMPLES
+========
+<?xml version="1.0" encoding="UTF-8"?>
+<testsuites disabled="" errors="" failures="" name="" tests="" time="">
+ <testsuite disabled="" errors="" failures="" hostname="" id=""
+ name="" package="" skipped="" tests="" time="" timestamp="">
+ <properties>
+ <property name="" value=""/>
+ </properties>
+ <testcase assertions="" classname="" name="" status="" time="">
+ <skipped/>
+ <error message="" type=""/>
+ <failure message="" type=""/>
+ <system-out/>
+ <system-err/>
+ </testcase>
+ <system-out/>
+ <system-err/>
+ </testsuite>
+</testsuites>
+
+Some of these items can occur multiple times:
+
+There can only be one testsuites element, since that's how XML works, but there can be multiple testsuite elements within the testsuites element.
+Each properties element can have multiple property children.
+Each testsuite element can have multiple testcase children.
+Each testcase element can have multiple error, failure, system-out, or system-err children:
+
+<testsuite tests="3">
+ <testcase classname="foo1" name="ASuccessfulTest"/>
+ <testcase classname="foo2" name="AnotherSuccessfulTest"/>
+ <testcase classname="foo3" name="AFailingTest">
+ <failure type="NotEnoughFoo"> details about failure </failure>
+ </testcase>
+</testsuite>
+
+*/
+
+/*
+ <testsuite name="" <!-- Full (class) name of the test for non-aggregated testsuite documents.
+ Class name without the package for aggregated testsuites documents. Required -->
+ tests="" <!-- The total number of tests in the suite, required. -->
+
+ disabled="" <!-- the total number of disabled tests in the suite. optional -->
+ errors="" <!-- The total number of tests in the suite that errored. An errored test is one that had an unanticipated problem,
+ for example an unchecked throwable; or a problem with the implementation of the test. optional -->
+ failures="" <!-- The total number of tests in the suite that failed. A failure is a test which the code has explicitly failed
+ by using the mechanisms for that purpose. e.g., via an assertEquals. optional -->
+ hostname="" <!-- Host on which the tests were executed. 'localhost' should be used if the hostname cannot be determined. optional -->
+ id="" <!-- Starts at 0 for the first testsuite and is incremented by 1 for each following testsuite -->
+ package="" <!-- Derived from testsuite/@name in the non-aggregated documents. optional -->
+ skipped="" <!-- The total number of skipped tests. optional -->
+ time="" <!-- Time taken (in seconds) to execute the tests in the suite. optional -->
+ timestamp="" <!-- when the test was executed in ISO 8601 format (2014-01-21T16:17:18). Timezone may not be specified. optional -->
+ >
+*/
+ result->createAttribute("name", "ADML Testing Main Testsuite");
+ int poolSize = a_testPool.size();
+ result->createAttribute("tests", poolSize);
+
+ result->createAttribute("errors", 0);
+ result->createAttribute("failures", a_statSummary.getFailedCount());
+ result->createAttribute("hostname", anna::functions::getHostname());
+ result->createAttribute("skipped", a_statSummary.getInitializedCount());
+
+ // Testcases:
+
+/*
+ <!-- testcase can appear multiple times, see /testsuites/testsuite@tests -->
+ <testcase name="" <!-- Name of the test method, required. -->
+ assertions="" <!-- number of assertions in the test case. optional -->
+ classname="" <!-- Full class name for the class the test method is in. required -->
+ status=""
+ time="" <!-- Time taken (in seconds) to execute the test. optional -->
+ >
+
+*/
+ int testcasesLapseMs = 0;
+ int startTimestampMs = 0;
+ double secs;
+ if (poolSize != 0) {
+ test_pool_it it_min = a_testPool.begin();
+ test_pool_it it_max = a_testPool.end();
+ startTimestampMs = (int)((*it_min).second->getStartTimestamp());
+ std::string debugSummary;
+
+ for (test_pool_it it = it_min; it != it_max; it++) {
+ anna::xml::Node* testcase = result->createChild("testcase");
+ auto tc = (*it).second;
+
+ testcasesLapseMs = (int)(tc->getLapseMs());
+ testcase->createAttribute("classname", "adml_testcase");
+ testcase->createAttribute("description", tc->getDescription());
+ testcase->createAttribute("status", TestCase::asText(tc->getState()));
+
+ secs = testcasesLapseMs / 1000.0;
+ testcase->createAttribute("time", anna::functions::asString(secs, "%.2f"));
+
+ if (tc->isFailed()) {
+ anna::xml::Node* failure = testcase->createChild("failure");
+ std::string text = "";
+ debugSummary = tc->getDebugSummary().asString();
+ if (debugSummary != "") {
+ text += "[Testcase debug summary]";
+ text += "<!--";
+ text += debugSummary;
+ text += "-->";
+ }
+ text += "[Testcase information (xml dump)]";
+ text += "<!--";
+ text += tc->asXMLString();
+ text += "-->";
+ failure->createText(text);
+ }
+ }
+ }
+
+ time_t startTimestamp = startTimestampMs/1000;
+ time(&startTimestamp);
+ char buf[sizeof "2011-10-08T07:07:09Z"];
+ strftime(buf, sizeof buf, "%FT%TZ", gmtime(&startTimestamp));
+ // this will work too, if your compiler doesn't support %F or %T:
+ // //strftime(buf, sizeof buf, "%Y-%m-%dT%H:%M:%SZ", gmtime(&now));
+ // std::cout << buf << "\n";
+ result->createAttribute("timestamp", buf);
+
+
+ return result;
+}
+
+std::string TestManager::asXMLString() const {
anna::xml::Node root("root");
return anna::xml::Compiler().apply(asXML(&root));
}
+std::string TestManager::junitAsXMLString() const {
+ anna::xml::Node root("root");
+ return anna::xml::Compiler().apply(junitAsXML(&root));
+}
+
+std::string TestManager::summaryCounts() const {
+
+ std::string result= "\nSummary Counts:\n";
+ unsigned int total = a_statSummary.getTotal();
+ result += "\nTotal: " + anna::functions::asString(total);
+ result += "\nInitialized: " + anna::functions::asString(a_statSummary.getInitializedCount());
+ result += "\nIn Progress: " + anna::functions::asString(a_statSummary.getInProgressCount());
+ unsigned int failed = a_statSummary.getFailedCount();
+ unsigned int success = a_statSummary.getSuccessCount();
+ result += "\nFailed: " + anna::functions::asString(failed);
+ result += "\nSuccess: " + anna::functions::asString(success);
+ std::string verdict = ((failed == 0) && (success > 0) && (total == success)) ? "PASS":"FAIL";
+ if (total != 0) {
+ result += std::string("\n\nVERDICT: ") + verdict;
+ }
+
+ return result;
+}
+
+std::string TestManager::summaryStates() const {
+
+ std::string result = "\nSummary States:\n";
+ const char *literal = "\n[%s] %s";
+ const char *secsLiteral = " (%.2f secs)";
+
+ int testcasesLapseMs = 0;
+ int startTimestampMs = 0;
+ double secs;
+ int poolSize = a_testPool.size();
+ if (poolSize != 0) {
+ test_pool_it it_min = a_testPool.begin();
+ test_pool_it it_max = a_testPool.end();
+ startTimestampMs = (int)((*it_min).second->getStartTimestamp());
+
+ for (test_pool_it it = it_min; it != it_max; it++) {
+ auto tc = (*it).second;
+
+ testcasesLapseMs = (int)(tc->getLapseMs());
+
+ result += anna::functions::asString(literal, TestCase::asText(tc->getState()), tc->getDescription().c_str());
+
+ if (testcasesLapseMs >= 0) {
+ secs = testcasesLapseMs / 1000.0;
+ result += anna::functions::asString(secsLiteral, secs);
+ }
+ }
+ }
+ else {
+ result +="\nNo test cases programmed !";
+ }
+
+ return result;
+}
+