+ } else if((opType == "test")) {
+ // test|<id>|<command>[|parameters] Add a new step to the test case ...
+ // test|ttps|<amount> Starts/resume the provided number of time ticks per second (ttps). The ADML starts ...
+ // test|next[|<sync-amount>] Forces the execution of the next test case(s) without waiting for test manager tick ...
+ // test|ip-limit[|amount] In-progress limit of test cases. No new test cases will be launched over this value ...
+ // test|repeats|<amount> Restarts the whole programmed test list when finished the amount number of times ...
+ // test|report|<initialized/in-progress/failed/success/[all]/none>[|[yes]|no]
+ // Enables/disables report generation for a certain test case state: initialized, in-progress ...
+ // test|report-hex[|[yes]|no] Reports could include the diameter messages in hexadecimal format. Disabled by default.
+ // test|goto|<id> Updates current test pointer position.
+ // test|look[|id] Show programmed test case for id provided, current when missing ...
+ // test|state[|id] Show test case state 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 ...
+
+
+ if(param1 == "ttps") {
+ if (numParams > 2)
+ throw anna::RuntimeException("Wrong body content format on HTTP Request. Check 'HELP.md' for more information.", ANNA_FILE_LOCATION);
+
+ bool success = ((param2 != "") ? testManager.configureTTPS(atoi(param2.c_str())) : false);
+ if (success) {
+ opt_response_content = "assigned new test launch rate to ";
+ opt_response_content += anna::functions::asString(atoi(param2.c_str()));
+ opt_response_content += " events per second";
+ }
+ else {
+ opt_response_content += "unable to configure the test rate provided";
+ }
+ }
+ else if (param1 == "next") {
+ if (numParams > 2)
+ throw anna::RuntimeException("Wrong body content format on HTTP Request. Check 'HELP.md' for more information.", ANNA_FILE_LOCATION);
+
+ int sync_amount = ((param2 != "") ? atoi(param2.c_str()) : 1);
+
+ if (sync_amount < 1)
+ throw anna::RuntimeException("The parameter 'sync-amount' must be a positive integer value", ANNA_FILE_LOCATION);
+
+ bool success = testManager.execTestCases(sync_amount);
+
+ opt_response_content = (success ? "" : "not completely " /* completed cycle and no repeats, rare case */);
+ opt_response_content += "processed ";
+ opt_response_content += anna::functions::asString(sync_amount);
+ opt_response_content += ((sync_amount > 1) ? " test cases synchronously" : " test case");
+ }
+ else if(param1 == "ip-limit") {
+ if (numParams > 2)
+ throw anna::RuntimeException("Wrong body content format on HTTP Request. Check 'HELP.md' for more information.", ANNA_FILE_LOCATION);
+
+ unsigned int limit;
+ if (param2 != "") {
+ limit = atoi(param2.c_str());
+ testManager.setInProgressLimit(limit);
+ opt_response_content = "new in-progress limit: ";
+ opt_response_content += (limit != UINT_MAX) ? anna::functions::asString(limit) : "<no limit>";
+ }
+ else {
+ opt_response_content = "in-progress limit amount: ";
+ limit = testManager.getInProgressLimit();
+ opt_response_content += (limit != UINT_MAX) ? anna::functions::asString(limit) : "<no limit>";
+ opt_response_content += "; currently there are ";
+ opt_response_content += anna::functions::asString(testManager.getInProgressCount());
+ opt_response_content += " test cases running";
+ }
+ }
+ else if(param1 == "repeats") {
+ if (numParams != 2)
+ throw anna::RuntimeException("Wrong body content format on HTTP Request. Check 'HELP.md' for more information.", ANNA_FILE_LOCATION);
+ int repeats = atoi(param2.c_str());
+ if (repeats < 0) repeats = -1;
+ testManager.setPoolRepeats(repeats);
+ std::string nolimit = (repeats != -1) ? "":" [no limit]";
+ opt_response_content += anna::functions::asString("Pool repeats: %d%s (current cycle: %d)", repeats, nolimit.c_str(), testManager.getPoolCycle());
+ }
+ else if(param1 == "report") {
+ if (numParams > 3)
+ throw anna::RuntimeException("Wrong body content format on HTTP Request. Check 'HELP.md' for more information.", ANNA_FILE_LOCATION);
+
+ if(param2 == "") param2 = "all";
+ if(param3 == "") param3 = "yes";
+ bool enable = (param3 == "yes");
+
+ if(param2 == "initialized")
+ testManager.setDumpInitializedReports(enable);
+ else if(param2 == "in-progress")
+ testManager.setDumpInProgressReports(enable);
+ else if(param2 == "failed")
+ testManager.setDumpFailedReports(enable);
+ else if(param2 == "success")
+ testManager.setDumpSuccessReports(enable);
+ else if(param2 == "all") {
+ param2 = "any";
+ testManager.setDumpAllReports(enable);
+ }
+ else if(param2 == "none") {
+ enable = !enable;
+ param2 = "any";
+ testManager.setDumpAllReports(enable);
+ }
+ else
+ throw anna::RuntimeException("Wrong body content format on HTTP Request. Check 'HELP.md' for more information.", ANNA_FILE_LOCATION);
+
+ opt_response_content += (enable ? "report enabled " : "report disabled ");
+ opt_response_content += "for tests in '";
+ opt_response_content += param2;
+ opt_response_content += "' state";
+ }
+ else if(param1 == "report-hex") {
+ if (numParams > 2)
+ throw anna::RuntimeException("Wrong body content format on HTTP Request. Check 'HELP.md' for more information.", ANNA_FILE_LOCATION);
+
+ if(param2 == "") param2 = "yes";
+ 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. Check 'HELP.md' for 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. Check 'HELP.md' for more information.", ANNA_FILE_LOCATION);
+
+ if(param2 == "") throw anna::RuntimeException("Missing id for test goto operation", ANNA_FILE_LOCATION);
+ int id = atoi(param2.c_str());
+ if (testManager.gotoTestCase(id)) {
+ opt_response_content = "position updated for id provided (";
+ }
+ else {
+ opt_response_content = "cannot found test id (";
+ }
+ opt_response_content += anna::functions::asString(id);
+ opt_response_content += ")";
+ }
+ else if(param1 == "run") {
+ if (numParams > 2)
+ throw anna::RuntimeException("Wrong body content format on HTTP Request. Check 'HELP.md' for more information.", ANNA_FILE_LOCATION);
+
+ if(param2 == "") throw anna::RuntimeException("Missing id for test run operation", ANNA_FILE_LOCATION);
+ int id = atoi(param2.c_str());
+ if (testManager.runTestCase(id)) {
+ opt_response_content = "test executed for id provided (";
+ }
+ else {
+ opt_response_content = "cannot found test id (";
+ }
+ opt_response_content += anna::functions::asString(id);
+ opt_response_content += ")";
+ }
+ else if(param1 == "look") {
+ if (numParams > 2)
+ throw anna::RuntimeException("Wrong body content format on HTTP Request. Check 'HELP.md' for more information.", ANNA_FILE_LOCATION);
+
+ int id = ((param2 != "") ? atoi(param2.c_str()) : -1);
+ anna::testing::TestCase *testCase = testManager.findTestCase(id);
+
+ if (testCase) {
+ response_content = testCase->asXMLString();
+ return true; // OK
+ }
+ else {
+ result = false;
+ if (id == -1) {
+ opt_response_content = "no current test case detected (testing started ?)";
+ }
+ else {
+ opt_response_content = "cannot found test id (";
+ opt_response_content += anna::functions::asString(id);
+ opt_response_content += ")";
+ }
+ }
+ }
+ else if(param1 == "state") {
+ if (numParams > 2)
+ throw anna::RuntimeException("Wrong body content format on HTTP Request. Check 'HELP.md' for more information.", ANNA_FILE_LOCATION);
+
+ int id = ((param2 != "") ? atoi(param2.c_str()) : -1);
+ anna::testing::TestCase *testCase = testManager.findTestCase(id);
+
+ if (testCase) {
+ response_content = anna::testing::TestCase::asText(testCase->getState());
+ return testCase->isSuccess();
+ }
+ else {
+ result = false;
+ if (id == -1) {
+ opt_response_content = "no current test case detected (testing started ?)";
+ }
+ else {
+ opt_response_content = "cannot found test id (";
+ opt_response_content += anna::functions::asString(id);
+ opt_response_content += ")";
+ }
+ }
+ }
+ else if (param1 == "interact") {
+ if (numParams != 2)
+ throw anna::RuntimeException("Wrong body content format on HTTP Request. Check 'HELP.md' for 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 = ((param3 != "") ? atoi(param3.c_str()) : -1);
+ anna::testing::TestCase *testCase = testManager.findTestCase(id);
+ if (testCase) {
+ if (amount == -1) {
+ testCase->makeInteractive(false);
+ opt_response_content = "interactive mode disabled";
+ }
+ else {
+ testCase->addInteractiveAmount(amount);
+ opt_response_content = "added interactive amount of ";
+ opt_response_content += anna::functions::asString(amount);
+ opt_response_content += " units";
+ if (amount == 0) opt_response_content += " (0: freezing a non-interactive testcase, no effect on already interactive)";
+ }
+ opt_response_content += " for test case id ";
+ opt_response_content += anna::functions::asString(id);
+ }
+ else {
+ result = false;
+ opt_response_content = "cannot found test id (";
+ opt_response_content += anna::functions::asString(id);
+ opt_response_content += ")";
+ }
+ }
+ else if(param1 == "reset") {
+ if (numParams > 3)
+ throw anna::RuntimeException("Wrong body content format on HTTP Request. Check 'HELP.md' for more information.", ANNA_FILE_LOCATION);
+
+ if(param2 == "") param2 = "soft";
+ if (param2 != "soft" && param2 != "hard")
+ throw anna::RuntimeException("Wrong body content format on HTTP Request. Check 'HELP.md' for more information.", ANNA_FILE_LOCATION);
+
+ int id = ((param3 != "") ? atoi(param3.c_str()) : -1);
+ anna::testing::TestCase *testCase = ((id != -1) ? testManager.findTestCase(id) : NULL);
+
+ if (testCase) {
+ bool done = testCase->reset(param2 == "hard");
+ opt_response_content = "test ";
+ opt_response_content += param2;
+ opt_response_content += " reset for id ";
+ opt_response_content += anna::functions::asString(id);
+ opt_response_content += done ? ": done": ": not done";
+ }
+ else {
+ if (id == -1) {
+ 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 {
+ result = false;
+ opt_response_content = "cannot found test id (";
+ opt_response_content += anna::functions::asString(id);
+ opt_response_content += ")";
+ }
+ }
+ }
+ else if(param1 == "auto-reset") {
+ if (numParams != 2)
+ throw anna::RuntimeException("Wrong body content format on HTTP Request. Check 'HELP.md' for more information.", ANNA_FILE_LOCATION);
+
+ if (param2 != "soft" && param2 != "hard")
+ throw anna::RuntimeException("Wrong body content format on HTTP Request. Check 'HELP.md' for 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. Check 'HELP.md' for 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. Check 'HELP.md' for 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. Check 'HELP.md' for more information.", ANNA_FILE_LOCATION);
+
+ if (testManager.clearPool()) {
+ opt_response_content = "all the programmed test cases have been dropped";
+ }
+ else {
+ opt_response_content = "there are not programmed test cases to be removed";
+ }
+ }
+ else if(param1 == "junit") {
+ response_content = testManager.junitAsXMLString();
+ return true; // OK
+ }
+ else if(param1 == "summary-counts") {
+ response_content = testManager.summaryCounts();
+ return true; // OK
+ }
+ else if(param1 == "summary-states") {
+ response_content = testManager.summaryStates();
+ return true; // OK
+ }
+ else if(param1 == "summary") {
+ response_content = testManager.asXMLString();
+ return true; // OK
+ }
+ else {
+ int id = atoi(param1.c_str());
+ if(id < 0)
+ throw anna::RuntimeException("Invalid test case identifier: must be a non-negative number", ANNA_FILE_LOCATION);
+
+ // 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>]
+ // delay| [msecs]
+ // wait<fe/fc>|[code]|[bitR]|[hopByHop]|[applicationId]|[sessionId]|[resultCode]|[msisdn]|[imsi]|[serviceContextId]
+ // wait<fe/fc>-answer|<step number>
+ // wait<fe/fc>-xml |<source_file>[|strict]
+ // wait<fe/fc>-hex |<source_file>[|strict]
+ if(param2 == "") throw anna::RuntimeException("Missing command for test id operation", ANNA_FILE_LOCATION);
+
+ // Commands:
+ if (param2 == "description") {
+ if (numParams > 3)
+ throw anna::RuntimeException("Wrong body content format on HTTP Request. Check 'HELP.md' for 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. Check 'HELP.md' for 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. Check 'HELP.md' for more information.", ANNA_FILE_LOCATION);
+ if(param3 == "") throw anna::RuntimeException("Missing milliseconds for 'timeout' command in test id operation", ANNA_FILE_LOCATION);
+ anna::Millisecond timeout = checkTimeMeasure("Test case timeout", param3);
+ testManager.getTestCase(id)->addTimeout(timeout); // creates / reuses
+ }
+ else if ((param2 == "sendxml2e")||(param2 == "sendxml2c")) {
+ if (numParams > 4)
+ throw anna::RuntimeException("Wrong body content format on HTTP Request. Check 'HELP.md' for more information.", ANNA_FILE_LOCATION);
+ if(param3 == "") throw anna::RuntimeException(anna::functions::asString("Missing xml file for '%s' command in test id operation", param2.c_str()), ANNA_FILE_LOCATION);
+ codecMsg.loadXMLFile(param3);
+ LOGWARNING(
+ if (!codecMsg.isRequest() && (param4 == ""))
+ anna::Logger::warning("Step number has not been provided. Take into account that this answer message will be sent 'as is' and sequence information could be wrong at the remote peer", ANNA_FILE_LOCATION);
+ );
+
+ updateOperatedOriginHostWithMessage(codecMsg);
+ int stepNumber = ((param4 != "") ? atoi(param4.c_str()):-1);
+
+ if (param2 == "sendxml2e")
+ testManager.getTestCase(id)->addSendDiameterXml2e(codecMsg.code(), getOperatedHost(), stepNumber); // creates / reuses
+ else
+ 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. Check 'HELP.md' for more information.", ANNA_FILE_LOCATION);
+ if(param3 == "") throw anna::RuntimeException("Missing milliseconds for 'delay' command in test id operation", ANNA_FILE_LOCATION);
+ anna::Millisecond delay = ((param3 == "0" /* special case */) ? (anna::Millisecond)0 : checkTimeMeasure("Test case delay step", param3));
+ testManager.getTestCase(id)->addDelay(delay); // creates / reuses
+ }
+
+// TODO(***)
+// The way to identify the test case, is through registered Session-Id values for
+// programmed requests. But this depends on the type of node. Acting as clients,
+// requests received have Session-Id values which are already registered with
+// one test case, causing an error if not found. Acting as servers, requests are
+// received over a diameter local server from a client which are generating that
+// Session-Id values. Then we know nothing about such values. The procedure in
+// this case is find out a test case not-started containing a condition which
+// comply with the incoming message, and reactivates it.
+// The other solution: register Session-Id values for answers send to client from a local diameter server.
+ else if ((param2 == "waitfe")||(param2 == "waitfc")) {
+ if (numParams > 11)
+ throw anna::RuntimeException("Wrong body content format on HTTP Request. Check 'HELP.md' for 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)->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);
+ }
+ }
+ else if ((param2 == "waitfe-hex")||(param2 == "waitfc-hex")) {
+ if (numParams > 4)
+ throw anna::RuntimeException("Wrong body content format on HTTP Request. Check 'HELP.md' for more information.", ANNA_FILE_LOCATION);
+ if(param3 == "") throw anna::RuntimeException(anna::functions::asString("Missing hex file for '%s' command in test id operation", param2.c_str()), ANNA_FILE_LOCATION);
+
+ // Get DataBlock from file with hex content:
+ if(!getDataBlockFromHexFile(param3, db_aux))
+ throw anna::RuntimeException("Error reading hex content from file provided", ANNA_FILE_LOCATION);
+
+ // Hexadecimal representation read from file:
+ std::string regexp = anna::functions::asHexString(db_aux);
+
+ // optional 'full':
+ if(param4 != "strict") {
+ //// If request, we will ignore sequence data:
+ //if (anna::diameter::codec::functions::requestBit(db_aux))
+ regexp.replace (24, 16, "[0-9A-Fa-f]{16}");
+
+ regexp.insert(0, "^");
+ regexp += "$";
+ }
+
+ bool fromEntity = (param2.substr(4,2) == "fe");
+ testManager.getTestCase(id)->addWaitDiameterRegexpHex(fromEntity, regexp);
+ }
+ else if ((param2 == "waitfe-xml")||(param2 == "waitfc-xml")) {
+ if (numParams > 4)
+ throw anna::RuntimeException("Wrong body content format on HTTP Request. Check 'HELP.md' for more information.", ANNA_FILE_LOCATION);
+ if(param3 == "") throw anna::RuntimeException(anna::functions::asString("Missing xml file for '%s' command in test id operation", param2.c_str()), ANNA_FILE_LOCATION);
+
+ codecMsg.loadXMLFile(param3);
+ std::string regexp = codecMsg.asXMLString(true /* normalization */);
+
+ // Now we must insert regular expressions in hop-by-hop, end-to-end and Origin-State-Id:
+
+ // optional 'full':
+ if(param4 != "strict") {
+ std::string::size_type pos, pos_1, pos_2;
+
+ pos = regexp.find("end-to-end-id=", 0u);
+ pos = regexp.find("\"", pos);
+ pos_1 = pos;
+ pos = regexp.find("\"", pos+1);
+ pos_2 = pos;
+ regexp.replace(pos_1 + 1, pos_2 - pos_1 - 1, "[0-9]+");
+
+ pos = regexp.find("hop-by-hop-id=", 0u);
+ pos = regexp.find("\"", pos);
+ pos_1 = pos;
+ pos = regexp.find("\"", pos+1);
+ pos_2 = pos;
+ regexp.replace(pos_1 + 1, pos_2 - pos_1 - 1, "[0-9]+");
+
+ // For this representation: <avp name="Origin-State-Id" data="1428633668"/>
+ //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]+");
+ // But we have this one: <avp data="1428633668" name="Origin-State-Id"/>
+ pos = regexp.find("Origin-State-Id", 0u);
+ pos = regexp.rfind("\"", pos);
+ pos = regexp.rfind("\"", pos-1);
+ pos = regexp.rfind("\"", 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)->addWaitDiameterRegexpXml(fromEntity, regexp);
+ }
+ else if (param2 == "sh-command") {
+ // Allow pipes in command:
+ //if (numParams > 4)
+ // throw anna::RuntimeException("Wrong body content format on HTTP Request. Check 'HELP.md' for more information.", ANNA_FILE_LOCATION);
+ if(param3 == "") throw anna::RuntimeException("Missing script/executable command-line for 'sh-command' in test id operation", ANNA_FILE_LOCATION);
+ std::string token = "|sh-command|";
+ std::string command = operation.substr(operation.find(token) + token.size());
+ testManager.getTestCase(id)->addCommand(command); // creates / reuses
+ }
+ else {
+ throw anna::RuntimeException("Wrong body content format on HTTP Request. Check 'HELP.md' for more information.", ANNA_FILE_LOCATION);
+ }
+ }
+
+ } else if((opType == "sendxml2c") || (opType == "sendhex2c")) {
+ anna::diameter::comm::Message *msg;