X-Git-Url: https://git.teslayout.com/public/public/public/?p=anna.git;a=blobdiff_plain;f=source%2Ftesting%2FTestManager.cpp;h=20a29a2f5a2f4336b832124458247a73953def92;hp=5f0f6f672916ccce3ad4e6e2dd40163ca1b40ecf;hb=2e2f6d4e2ffe1c8b86c812807f0e501ab78f56f9;hpb=88cd8ffad493971ae4704ed007d8430c1d3fd7eb diff --git a/source/testing/TestManager.cpp b/source/testing/TestManager.cpp index 5f0f6f6..20a29a2 100644 --- a/source/testing/TestManager.cpp +++ b/source/testing/TestManager.cpp @@ -20,6 +20,7 @@ #include #include #include +#include #include #include #include @@ -91,6 +92,7 @@ TestManager::TestManager() : a_dumpSuccessReports = false; a_dumpHexMessages = false; + a_dumpStdout = false; a_synchronousAmount = 1; a_poolRepeats = 0; // repeat disabled by default a_poolCycle = 1; @@ -266,12 +268,12 @@ TestCase *TestManager::findTestCase(unsigned int id) const throw() { // id = -1 return NULL; } -TestCase *TestManager::getTestCase(unsigned int id) throw() { +TestCase *TestManager::getTestCase(unsigned int id, const std::string &description) throw() { 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; } @@ -428,7 +430,7 @@ void TestManager::receiveDiameterMessage(const anna::DataBlock &message, const a } // 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 += "'; "; @@ -469,7 +471,7 @@ void TestManager::receiveDiameterMessage(const anna::DataBlock &message, const a } // 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 += "'; "; @@ -512,6 +514,7 @@ throw() { 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) { @@ -536,8 +539,210 @@ throw() { return result; } +anna::xml::Node* TestManager::junitAsXML(anna::xml::Node* parent) const +throw() { + // 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 +======== + + + + + + + + + + + + + + + + + + +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: + + + + + + details about failure + + + +*/ + +/* + + tests="" + + disabled="" + errors="" + failures="" + hostname="" + id="" + package="" + skipped="" + time="" + timestamp="" + > +*/ + 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: + +/* + + + assertions="" + classname="" + status="" + time="" + > + +*/ + 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 += "[Testcase information (xml dump)]"; + 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 throw() { anna::xml::Node root("root"); return anna::xml::Compiler().apply(asXML(&root)); } +std::string TestManager::junitAsXMLString() const throw() { + anna::xml::Node root("root"); + return anna::xml::Compiler().apply(junitAsXML(&root)); +} + +std::string TestManager::summaryCounts() const throw() { + + 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 throw() { + + 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; +} +