#include <anna/diameter.comm/ApplicationMessageOamModule.hpp>
#include <anna/testing/defines.hpp>
#include <anna/xml/xml.hpp>
+#include <anna/diameter.comm/OriginHost.hpp>
+#include <anna/diameter.comm/OriginHostManager.hpp>
#include <Procedure.hpp>
// Process
#include <Launcher.hpp>
#include <MyDiameterEngine.hpp>
-#include <anna/diameter.comm/OriginHost.hpp>
#include <anna/testing/TestManager.hpp>
#include <anna/testing/TestCase.hpp>
//a_admlMinResolution = (anna::Millisecond)100;
a_counterRecorderClock = NULL;
- // a_originHosts.clear();
a_workingNode = NULL;
a_httpServerSocket = NULL;
burstLog = (*it)->getAttribute("burstLog", false /* no exception */); // (yes | no)
// Basic checkings:
- origin_hosts_it nodeIt = a_originHosts.find(originHost->getValue());
- if (nodeIt != a_originHosts.end()) {
+ anna::diameter::comm::OriginHostManager &ohm = anna::diameter::comm::OriginHostManager::instantiate();
+ anna::diameter::comm::OriginHost *oh = ohm.getOriginHost(originHost->getValue());
+ if (oh) {
std::string msg = "Already registered such Origin-Host: "; msg += originHost->getValue();
throw anna::RuntimeException(msg, ANNA_FILE_LOCATION);
}
if (eventOperation) commEngine->lazyInitialize();
// Node and Codec Engine registration ///////////////////////////////////////////////////////
- a_originHosts[originHost->getValue()] = a_workingNode;
+ ohm.registerOriginHost(originHost->getValue(), a_workingNode);
/////////////////////////////////////////////////////////////////////////////////////////////
}
}
bool Launcher::setWorkingNode(const std::string &name) throw() {
bool result = false;
- origin_hosts_it nodeIt = a_originHosts.find(name);
- if (nodeIt == a_originHosts.end()) {
- LOGWARNING(
- std::string msg = "Unknown node with name '"; msg += name; msg += "'. Ignoring ...";
- anna::Logger::warning(msg, ANNA_FILE_LOCATION);
- );
- }
- else {
- a_workingNode = const_cast<anna::diameter::comm::OriginHost*>(nodeIt->second);
+ anna::diameter::comm::OriginHostManager &ohm = anna::diameter::comm::OriginHostManager::instantiate();
+ anna::diameter::comm::OriginHost *oh = ohm.getOriginHost(name);
+
+ if (oh) {
+ a_workingNode = const_cast<anna::diameter::comm::OriginHost*>(oh);
result = true;
}
return result;
}
-anna::diameter::comm::OriginHost *Launcher::getOriginHost(const std::string &oh) const throw(anna::RuntimeException) {
- origin_hosts_it it = a_originHosts.find(oh);
- if (it != a_originHosts.end()) return it->second;
- throw anna::RuntimeException(anna::functions::asString("There is no origin host registered as '%s' (set Origin-Host avp correctly or force a specific host with 'node' operation)", oh.c_str()), ANNA_FILE_LOCATION);
+anna::diameter::comm::OriginHost *Launcher::getOriginHost(const std::string &name) const throw(anna::RuntimeException) {
+ anna::diameter::comm::OriginHostManager &ohm = anna::diameter::comm::OriginHostManager::instantiate();
+ anna::diameter::comm::OriginHost *result = ohm.getOriginHost(name);
+
+ if (!result)
+ throw anna::RuntimeException(anna::functions::asString("There is no origin host registered as '%s' (set Origin-Host avp correctly or force a specific host with 'node' operation)", name.c_str()), ANNA_FILE_LOCATION);
+
+ return result;
}
anna::diameter::comm::OriginHost *Launcher::getOriginHost(const anna::diameter::codec::Message &message) const throw(anna::RuntimeException) {
return (getOriginHost(originHost));
}
+bool Launcher::uniqueOriginHost() const throw() {
+ anna::diameter::comm::OriginHostManager &ohm = anna::diameter::comm::OriginHostManager::instantiate();
+ return (ohm.size() == 1);
+}
+
+
void Launcher::updateOperatedOriginHostWithMessage(const anna::diameter::codec::Message &message) throw(anna::RuntimeException) {
if (!a_operatedHost) // priority for working node by mean 'node' operation
a_operatedHost = getOriginHost(message);
// Counters record procedure:
const char *varname = "cntRecordPeriod";
- anna::Millisecond cntRecordPeriod = (cl.exists(varname)) ? checkTimeMeasure(varname, cl.getValue(varname)) : (anna::Millisecond)300000;
+ anna::Millisecond cntRecordPeriod;
+ try {
+ cntRecordPeriod = (cl.exists(varname)) ? checkTimeMeasure(varname, cl.getValue(varname)) : (anna::Millisecond)300000;
+ }
+ catch(anna::RuntimeException &ex) {
+ if (cntRecordPeriod != 0) throw ex;
+ }
+
if(cntRecordPeriod != 0) {
a_counterRecorderClock = new MyCounterRecorderClock("Counters record procedure clock", cntRecordPeriod); // clock
std::string cntDir = ".";
throw(anna::RuntimeException) {
LOGMETHOD(anna::TraceMethod tm("Launcher", "run", ANNA_FILE_LOCATION));
CommandLine& cl(anna::CommandLine::instantiate());
- anna::diameter::stack::Engine &stackEngine = anna::diameter::stack::Engine::instantiate();
+ anna::diameter::stack::Engine::instantiate();
// Start time:
a_start_time.setNow();
// Start client connections //////////////////////////////////////////////////////////////////////////////////
MyDiameterEntity *entity;
- for (origin_hosts_it it = a_originHosts.begin(); it != a_originHosts.end(); it++) {
+ anna::diameter::comm::OriginHostManager &ohm = anna::diameter::comm::OriginHostManager::instantiate();
+ for (diameter::comm::origin_hosts_it it = ohm.begin(); it != ohm.end(); it++) {
entity = (MyDiameterEntity *)(it->second->getEntity());
if (entity) entity->bind();
}
a_workingNode->getCommEngine()->resetStatistics();
}
else {
- for (origin_hosts_it it = a_originHosts.begin(); it != a_originHosts.end(); it++) {
+ anna::diameter::comm::OriginHostManager &ohm = anna::diameter::comm::OriginHostManager::instantiate();
+ for (diameter::comm::origin_hosts_it it = ohm.begin(); it != ohm.end(); it++) {
it->second->getCommEngine()->resetStatistics();
}
}
anna::diameter::codec::OamModule::instantiate().resetCounters();
}
+void Launcher::signalTerminate() throw(anna::RuntimeException) {
+ LOGMETHOD(anna::TraceMethod tm("Launcher", "signalTerminate", ANNA_FILE_LOCATION));
+
+ forceCountersRecord();
+
+ a_communicator->terminate ();
+ comm::Application::signalTerminate ();
+}
+
void Launcher::signalUSR2() throw(anna::RuntimeException) {
std::string inputFile = getSignalUSR2InputFile();
result += "\n values (Session-Id, Subscriber-Id, etc.).";
result += "\n";
result += "\n <command>: commands to be executed for the test id provided. Each command programmed";
- result += "\n constitutes a test case 'step', numbered from 1 to N.";
+ result += "\n constitutes a test case 'step', numbered from 1 to N, with an exception for";
+ result += "\n 'description' which is used to describe the test case:";
+ result += "\n";
+ result += "\n description|<description> Sets a test case description. Test cases by default are";
+ result += "\n constructed with description 'Testcase_<id>'.";
+ result += "\n";
+ result += "\n ip-limit[|amount] In-progress limit of test cases controlled from this test.";
+ result += "\n No new test cases will be launched over this value (test";
+ result += "\n manager tick work will be ignored). Zero-value is equivalent";
+ result += "\n to stop the clock tick, -1 is used to specify 'no limit' which";
+ result += "\n is the default. For missing amount, value of 1 is applied.";
result += "\n";
result += "\n timeout|<msecs> Sets an asynchronous timer to restrict the maximum timeout";
result += "\n until last test step. Normally, this command is invoked";
result += "\n source file (xml representation). Fix mode must be enabled to avoid";
result += "\n unexpected matching behaviour. If you need a strict matching you";
result += "\n must add parameter 'strict', if not, regexp is built ignoring sequence";
- result += "\n information (hop-by-hop-id=\"[0-9]+\" end-to-end-id=\"[0-9]+\").";
+ result += "\n information (hop-by-hop-id=\"[0-9]+\" end-to-end-id=\"[0-9]+\") and";
+ result += "\n Origin-State-Id value.";
result += "\n All LF codes will be internally removed when comparison is executed";
result += "\n in order to ease xml content configuration.";
result += "\n";
result += "\n next programmed test cases (1 by default). This event works regardless the timer tick";
result += "\n function, but it is normally used with the test manager tick stopped.";
result += "\n";
- result += "\n test|ip-limit[|amount] In-progress limit of test cases. No new test cases will be launched over this value";
- result += "\n (test Manager tick work will be ignored). Zero-value is equivalent to stop the clock.";
- result += "\n tick, -1 is used to specify 'no limit' which is the default. If missing amount, the";
- result += "\n limit and current amount of in-progress test cases will be shown.";
+ result += "\n test|ip-limit[|amount] In-progress limit of test cases established from global context. This value will be";
+ result += "\n overwritten if used at test case level when the corresponding test step is executed.";
+ result += "\n Anyway, the meaning is the same in both contexts. But now, when the amount is missing,";
+ result += "\n the limit and current amount of in-progress test cases will be shown.";
result += "\n";
result += "\n test|goto|<id> Updates current test pointer position.";
result += "\n";
result += "\n Test cases reports are not dumped on process context (too many information in general).";
result += "\n The report contains context information in every moment: this operation acts as a snapshot.";
result += "\n";
- result += "\n test|interact|amount|id Makes interactive a specific test case id. The amount is the margin of execution steps";
- result += "\n to be done. Normally, we will execute 'test|interact|0|<test case id>', which means that";
+ result += "\n test|interact|amount[|id] Makes interactive a specific test case id. The amount is the margin of execution steps";
+ result += "\n to be done. Normally, we will execute 'test|interact|0[|<test case id>]', which means that";
result += "\n the test case is selected to be interactive, but no step is executed. Then you have to";
result += "\n interact with positive amounts (usually 1), executing the provided number of steps if";
result += "\n they are ready and fulfill the needed conditions. The value of 0, implies no execution";
result += "\n steps margin, which could be useful to 'freeze' a test in the middle of its execution.";
result += "\n You could also provide -1 to make it non-interactive resuming it from the current step.";
+ result += "\n By default, current test case id is selected for interaction.";
result += "\n";
result += "\n test|reset|<[soft]/hard>[|id] Reset the test case for id provided, all the tests when missing. It could be hard/soft:";
result += "\n - hard: you probably may need to stop the load rate before. This operation initializes";
result += "\n been done before. Test cases state & data will be reset (when achieved again), but general";
result += "\n statistics and counters will continue measuring until reset with 'collect' operation.";
result += "\n";
+ result += "\n test|auto-reset|<soft|hard> When cycling, current test cases can be soft (default) or hard reset. If no timeout has";
+ result += "\n been configured for the test case, hard reset could prevent stuck on the next cycle for";
+ result += "\n those test cases still in progress.";
+ result += "\n";
+ result += "\n test|initialized Shows the number of initialized test cases. Zero-value means that everything was processed";
+ result += " or not initiated yet.\n";
+ result += "\n";
+ result += "\n test|finished Shows the number of finished (successful or failed) test cases.";
+ result += "\n";
result += "\n test|clear Clears all the programmed test cases and stop testing (if in progress).";
result += "\n";
+ result += "\n test|junit Shows the junit report in the moment of execution.";
+ result += "\n";
+ result += "\n test|summary-counts Test manager counts report. Counts by state and prints total verdict.";
+ result += "\n";
+ result += "\n test|summary-states Test manager states report.";
+ result += "\n";
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 enabled because the programmed test cases dumps could be heavy (anyway you could enable the";
result += "\n";
result += "\n test|report-hex[|[yes]|no] Reports could include the diameter messages in hexadecimal format. Disabled by default.";
result += "\n";
+ result += "\n test|dump-stdout[|[yes]|no] Test manager information is dumped into stdout.";
+ result += "\n";
result += "\n";
result += "\n------------------------------------------------------------------------------------- Dynamic procedure";
result += "\n";
if (args == "" && op_size != 7)
throw anna::RuntimeException("Wrong body content format on HTTP Request. Use 'help' management command to see more information.", ANNA_FILE_LOCATION);
try {
- p.execute(args, response_content, getWorkingNode());
+ p.execute(args, response_content);
}
catch(anna::RuntimeException &ex) {
ex.trace();
// test|look[|id] Show programmed test case for id provided, current when missing ...
// 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|auto-reset|<soft|hard> When cycling, current test cases can be soft (default) or hard reset ...
// test|clear Clears all the programmed test cases.
// test|summary Test manager general report (number of test cases, counts by state ...
testManager.setDumpHex((param2 == "yes"));
opt_response_content += (testManager.getDumpHex() ? "report includes hexadecimal messages" : "report excludes hexadecimal messages");
}
+ else if(param1 == "dump-stdout") {
+ if (numParams > 2)
+ throw anna::RuntimeException("Wrong body content format on HTTP Request. Use 'help' management command to see more information.", ANNA_FILE_LOCATION);
+
+ if(param2 == "") param2 = "yes";
+ testManager.setDumpStdout((param2 == "yes"));
+ opt_response_content += (testManager.getDumpHex() ? "test manager dumps progress into stdout" : "test manager does not dump progress into stdout");
+ }
else if(param1 == "goto") {
if (numParams > 2)
throw anna::RuntimeException("Wrong body content format on HTTP Request. Use 'help' management command to see more information.", ANNA_FILE_LOCATION);
}
}
else if (param1 == "interact") {
- if (numParams != 3)
+ if (numParams != 2)
throw anna::RuntimeException("Wrong body content format on HTTP Request. Use 'help' management command to see more information.", ANNA_FILE_LOCATION);
int amount = atoi(param2.c_str());
if (amount < -1)
throw anna::RuntimeException("Interactive amount must be -1 (to disable interactive mode) or a positive number.", ANNA_FILE_LOCATION);
- int id = atoi(param3.c_str());
+ int id = ((param3 != "") ? atoi(param3.c_str()) : -1);
anna::testing::TestCase *testCase = testManager.findTestCase(id);
if (testCase) {
if (amount == -1) {
anna::testing::TestCase *testCase = ((id != -1) ? testManager.findTestCase(id) : NULL);
if (testCase) {
- bool done = testCase->reset((param2 == "hard") ? true:false);
+ bool done = testCase->reset(param2 == "hard");
opt_response_content = "test ";
opt_response_content += param2;
opt_response_content += " reset for id ";
}
else {
if (id == -1) {
- bool anyReset = testManager.resetPool((param2 == "hard") ? true:false);
+ bool anyReset = testManager.resetPool(param2 == "hard");
opt_response_content = param2; opt_response_content += " reset have been sent to all programmed tests: "; opt_response_content += anyReset ? "some/all have been reset" : "nothing was reset";
}
else {
}
}
}
+ else if(param1 == "auto-reset") {
+ if (numParams != 2)
+ throw anna::RuntimeException("Wrong body content format on HTTP Request. Use 'help' management command to see more information.", ANNA_FILE_LOCATION);
+
+ if (param2 != "soft" && param2 != "hard")
+ throw anna::RuntimeException("Wrong body content format on HTTP Request. Use 'help' management command to see more information.", ANNA_FILE_LOCATION);
+
+ testManager.setAutoResetHard(param2 == "hard");
+ opt_response_content += anna::functions::asString("Auto-reset configured to '%s'", param2.c_str());
+ }
+ else if(param1 == "initialized") {
+ if (numParams > 1)
+ throw anna::RuntimeException("Wrong body content format on HTTP Request. Use 'help' management command to see more information.", ANNA_FILE_LOCATION);
+
+ opt_response_content = anna::functions::asString("%lu", testManager.getInitializedCount());
+ }
+ else if(param1 == "finished") {
+ if (numParams > 1)
+ throw anna::RuntimeException("Wrong body content format on HTTP Request. Use 'help' management command to see more information.", ANNA_FILE_LOCATION);
+
+ opt_response_content = anna::functions::asString("%lu", testManager.getFinishedCount());
+ }
else if(param1 == "clear") {
if (numParams > 1)
throw anna::RuntimeException("Wrong body content format on HTTP Request. Use 'help' management command to see more information.", ANNA_FILE_LOCATION);
opt_response_content = "there are not programmed test cases to be removed";
}
}
+ else if(param1 == "junit") {
+ response_content = testManager.junitAsXMLString();
+ return;
+ }
+ else if(param1 == "summary-counts") {
+ response_content = testManager.summaryCounts();
+ return;
+ }
+ else if(param1 == "summary-states") {
+ response_content = testManager.summaryStates();
+ return;
+ }
else if(param1 == "summary") {
response_content = testManager.asXMLString();
return;
// PARAM: 1 2 3 4 5 6 7 8 9 10 11
// test|<id>|<command>
+ // description|<description>
+ // ip-limit[|<iplimit>]
// timeout| <msecs>
// sendxml2e| <file>[|<step number>]
// sendxml2c| <file>[|<step number>]
if(param2 == "") throw anna::RuntimeException("Missing command for test id operation", ANNA_FILE_LOCATION);
// Commands:
- if (param2 == "timeout") {
+ if (param2 == "description") {
+ if (numParams > 3)
+ throw anna::RuntimeException("Wrong body content format on HTTP Request. Use 'help' management command to see more information.", ANNA_FILE_LOCATION);
+ if(param3 == "") throw anna::RuntimeException("Missing description for test case", ANNA_FILE_LOCATION);
+ testManager.getTestCase(id)->setDescription(param3); // creates / reuses
+ }
+ else if (param2 == "ip-limit") {
+ if (numParams > 3)
+ throw anna::RuntimeException("Wrong body content format on HTTP Request. Use 'help' management command to see more information.", ANNA_FILE_LOCATION);
+ unsigned int limit = (param3 == "") ? 1 : atoi(param3.c_str());
+ testManager.getTestCase(id)->addIpLimit(limit); // creates / reuses
+ }
+ else if (param2 == "timeout") {
if (numParams > 3)
throw anna::RuntimeException("Wrong body content format on HTTP Request. Use 'help' management command to see more information.", ANNA_FILE_LOCATION);
if(param3 == "") throw anna::RuntimeException("Missing milliseconds for 'timeout' command in test id operation", ANNA_FILE_LOCATION);
int stepNumber = ((param4 != "") ? atoi(param4.c_str()):-1);
if (param2 == "sendxml2e")
- testManager.getTestCase(id)->addSendxml2e(codecMsg.code(), getOperatedHost(), stepNumber); // creates / reuses
+ testManager.getTestCase(id)->addSendDiameterXml2e(codecMsg.code(), getOperatedHost(), stepNumber); // creates / reuses
else
- testManager.getTestCase(id)->addSendxml2c(codecMsg.code(), getOperatedHost(), stepNumber); // creates / reuses
+ testManager.getTestCase(id)->addSendDiameterXml2c(codecMsg.code(), getOperatedHost(), stepNumber); // creates / reuses
}
else if (param2 == "delay") {
if (numParams > 3)
throw anna::RuntimeException("Wrong body content format on HTTP Request. Use 'help' management command to see more information.", ANNA_FILE_LOCATION);
if (param3 != "" || param4 != "" || param5 != "" || param6 != "" || param7 != "" || param8 != "" || param9 != "" || param10 != "" || param11 != "") {
bool fromEntity = (param2.substr(4,2) == "fe");
- testManager.getTestCase(id)->addWait(fromEntity, param3, param4, param5, param6, param7, param8, param9, param10, param11);
+ testManager.getTestCase(id)->addWaitDiameter(fromEntity, param3, param4, param5, param6, param7, param8, param9, param10, param11);
}
else {
throw anna::RuntimeException(anna::functions::asString("Missing condition for '%s' command in test id operation", param2.c_str()), ANNA_FILE_LOCATION);
}
bool fromEntity = (param2.substr(4,2) == "fe");
- testManager.getTestCase(id)->addWaitRegexpHex(fromEntity, regexp);
+ testManager.getTestCase(id)->addWaitDiameterRegexpHex(fromEntity, regexp);
}
else if ((param2 == "waitfe-xml")||(param2 == "waitfc-xml")) {
if (numParams > 4)
/*
std::string s_from = "hop-by-hop-id=\"[0-9]+\" end-to-end-id=\"[0-9]+\"";
std::string s_to = s_from;
+ std::string s_from2 = "avp name=\"Origin-State-Id\" data=\"[0-9]+\"";
+ std::string s_to2 = s_from2;
try {
regexp = std::regex_replace (regexp, std::regex(s_from), s_to);
+ regexp = std::regex_replace (regexp, std::regex(s_from2), s_to2);
}
catch (const std::regex_error& e) {
throw anna::RuntimeException(e.what(), ANNA_FILE_LOCATION);
}
+
*/
std::string::size_type pos, pos_1, pos_2;
pos_2 = pos;
regexp.replace(pos_1 + 1, pos_2 - pos_1 - 1, "[0-9]+");
+ pos = regexp.find("Origin-State-Id", 0u);
+ pos = regexp.find("\"", pos);
+ pos = regexp.find("\"", pos+1);
+ pos_1 = pos;
+ pos = regexp.find("\"", pos+1);
+ pos_2 = pos;
+ regexp.replace(pos_1 + 1, pos_2 - pos_1 - 1, "[0-9]+");
+
//regexp.insert(0, "^");
//regexp += "$";
}
bool fromEntity = (param2.substr(4,2) == "fe");
- testManager.getTestCase(id)->addWaitRegexpXml(fromEntity, regexp);
+ testManager.getTestCase(id)->addWaitDiameterRegexpXml(fromEntity, regexp);
}
else if (param2 == "sh-command") {
// Allow pipes in command:
result->createAttribute("InitialWorkingDirectory", a_initialWorkingDirectory);
result->createAttribute("SecondsLifeTime", anna::time::functions::lapsedMilliseconds() / 1000);
// Diameter:
- for (origin_hosts_it it = a_originHosts.begin(); it != a_originHosts.end(); it++) {
+ anna::diameter::comm::OriginHostManager &ohm = anna::diameter::comm::OriginHostManager::instantiate();
+ for (diameter::comm::origin_hosts_it it = ohm.begin(); it != ohm.end(); it++) {
it->second->asXML(result);
}