From e688b5354af3a5fe0add859710cae41ffe123f65 Mon Sep 17 00:00:00 2001 From: "Eduardo Ramos Testillano (eramedu)" Date: Mon, 11 May 2020 05:10:31 +0200 Subject: [PATCH] Add third work package for REST API implementation Start with FSM Testing --- example/diameter/launcher/EventOperation.cpp | 261 +++++-- example/diameter/launcher/EventOperation.hpp | 21 +- example/diameter/launcher/Launcher.hpp | 3 +- example/diameter/launcher/MyHandler.cpp | 166 +++-- example/diameter/launcher/resources/HELP.md | 660 +++++++++++++++++- .../ct/fsm-testing/test-clear_test.py | 14 + .../ct/fsm-testing/testid-delay_test.py | 19 + .../ct/fsm-testing/testid-description_test.py | 19 + .../ct/fsm-testing/testid-ip-limit_test.py | 19 + .../ct/fsm-testing/testid-sendmsg2c_test.py | 19 + .../ct/fsm-testing/testid-sendmsg2e_test.py | 19 + .../ct/fsm-testing/testid-sh-command_test.py | 19 + .../ct/fsm-testing/testid-timeout_test.py | 19 + .../ct/fsm-testing/testid-waitfc-hex_test.py | 19 + .../ct/fsm-testing/testid-waitfc-msg_test.py | 19 + .../ct/fsm-testing/testid-waitfe-hex_test.py | 19 + .../ct/fsm-testing/testid-waitfe-msg_test.py | 19 + .../ct/fsm-testing/testid-waitfe_test.py | 19 + .../ct/resources/condition-request.json | 8 + 19 files changed, 1217 insertions(+), 144 deletions(-) create mode 100644 example/diameter/launcher/resources/rest_api/ct/fsm-testing/test-clear_test.py create mode 100644 example/diameter/launcher/resources/rest_api/ct/fsm-testing/testid-delay_test.py create mode 100644 example/diameter/launcher/resources/rest_api/ct/fsm-testing/testid-description_test.py create mode 100644 example/diameter/launcher/resources/rest_api/ct/fsm-testing/testid-ip-limit_test.py create mode 100644 example/diameter/launcher/resources/rest_api/ct/fsm-testing/testid-sendmsg2c_test.py create mode 100644 example/diameter/launcher/resources/rest_api/ct/fsm-testing/testid-sendmsg2e_test.py create mode 100644 example/diameter/launcher/resources/rest_api/ct/fsm-testing/testid-sh-command_test.py create mode 100644 example/diameter/launcher/resources/rest_api/ct/fsm-testing/testid-timeout_test.py create mode 100644 example/diameter/launcher/resources/rest_api/ct/fsm-testing/testid-waitfc-hex_test.py create mode 100644 example/diameter/launcher/resources/rest_api/ct/fsm-testing/testid-waitfc-msg_test.py create mode 100644 example/diameter/launcher/resources/rest_api/ct/fsm-testing/testid-waitfe-hex_test.py create mode 100644 example/diameter/launcher/resources/rest_api/ct/fsm-testing/testid-waitfe-msg_test.py create mode 100644 example/diameter/launcher/resources/rest_api/ct/fsm-testing/testid-waitfe_test.py create mode 100644 example/diameter/launcher/resources/rest_api/ct/resources/condition-request.json diff --git a/example/diameter/launcher/EventOperation.cpp b/example/diameter/launcher/EventOperation.cpp index 935940d..7709fb1 100644 --- a/example/diameter/launcher/EventOperation.cpp +++ b/example/diameter/launcher/EventOperation.cpp @@ -36,7 +36,8 @@ //#include //#include #include -//#include +#include +#include //#include //#include #include @@ -50,7 +51,7 @@ //#include #include #include -//#include +#include //#include @@ -577,8 +578,17 @@ bool EventOperation::answermsg_action_2c(std::string &response, const std::strin bool EventOperation::test_id__description(std::string &response, unsigned int id, const std::string & description) { Launcher& my_app = static_cast (anna::app::functions::getApp()); + anna::testing::TestManager &testManager = anna::testing::TestManager::instantiate(); - + try { + testManager.getTestCase(id)->setDescription(description); // creates / reuses + response = "Done"; + } + catch(anna::RuntimeException &ex) { + ex.trace(); + response += "invalid ip-limit"; + return false; + } return true; // OK } @@ -586,8 +596,17 @@ bool EventOperation::test_id__description(std::string &response, unsigned int id bool EventOperation::test_id__ip_limit(std::string &response, unsigned int id, int amount) { Launcher& my_app = static_cast (anna::app::functions::getApp()); + anna::testing::TestManager &testManager = anna::testing::TestManager::instantiate(); - + try { + testManager.getTestCase(id)->addIpLimit(amount); // creates / reuses + response = "Done"; + } + catch(anna::RuntimeException &ex) { + ex.trace(); + response += "invalid ip-limit"; + return false; + } return true; // OK } @@ -595,26 +614,55 @@ bool EventOperation::test_id__ip_limit(std::string &response, unsigned int id, i bool EventOperation::test_id__timeout(std::string &response, unsigned int id, int msecs) { Launcher& my_app = static_cast (anna::app::functions::getApp()); + anna::testing::TestManager &testManager = anna::testing::TestManager::instantiate(); - + try { + anna::Millisecond timeout = my_app.checkTimeMeasure("Test case timeout", anna::functions::asString(msecs)); + testManager.getTestCase(id)->addTimeout(timeout); // creates / reuses + response = "Done"; + } + catch(anna::RuntimeException &ex) { + ex.trace(); + response += "invalid timeout"; + return false; + } return true; // OK } -bool EventOperation::test_id__sendmsg2e(std::string &response, unsigned int id, const std::string & diameterJson, int stepNumber) { +bool EventOperation::test_id__sendmsg2e_2c(std::string &response, unsigned int id, bool _2e_or_2c, const std::string & diameterJson, int stepNumber) { Launcher& my_app = static_cast (anna::app::functions::getApp()); + anna::testing::TestManager &testManager = anna::testing::TestManager::instantiate(); + bool success; + std::string diameterXml = anna::json::functions::json2xml(diameterJson, success); + if (!success) { + response += "json to xml failed, unable to load message !"; + return false; + } + anna::diameter::codec::Message codecMsg; // auxiliary codec message + codecMsg.loadXMLString(diameterXml); + LOGWARNING( + if (!codecMsg.isRequest() && (stepNumber == -1)) + 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); + ); - return true; // OK -} - -bool EventOperation::test_id__sendmsg2c(std::string &response, unsigned int id, const std::string & diameterJson, int stepNumber) { - - Launcher& my_app = static_cast (anna::app::functions::getApp()); - + try { + my_app.updateOperatedOriginHostWithMessage(codecMsg); + if (_2e_or_2c) + testManager.getTestCase(id)->addSendDiameterXml2e(codecMsg.code(), my_app.getOperatedHost(), stepNumber); // creates / reuses + else + testManager.getTestCase(id)->addSendDiameterXml2c(codecMsg.code(), my_app.getOperatedHost(), stepNumber); // creates / reuses + response = "Done"; + } + catch(anna::RuntimeException &ex) { + ex.trace(); + response += "failed"; + return false; + } return true; // OK } @@ -622,8 +670,18 @@ bool EventOperation::test_id__sendmsg2c(std::string &response, unsigned int id, bool EventOperation::test_id__delay(std::string &response, unsigned int id, int msecs) { Launcher& my_app = static_cast (anna::app::functions::getApp()); + anna::testing::TestManager &testManager = anna::testing::TestManager::instantiate(); - + try { + anna::Millisecond delay = ((msecs == 0 /* special case */) ? (anna::Millisecond)0 : my_app.checkTimeMeasure("Test case delay step", anna::functions::asString(msecs))); + testManager.getTestCase(id)->addDelay(delay); // creates / reuses + response = "Done"; + } + catch(anna::RuntimeException &ex) { + ex.trace(); + response += "invalid delay"; + return false; + } return true; // OK } @@ -631,62 +689,164 @@ bool EventOperation::test_id__delay(std::string &response, unsigned int id, int bool EventOperation::test_id__sh_command(std::string &response, unsigned int id, const std::string & script) { Launcher& my_app = static_cast (anna::app::functions::getApp()); + anna::testing::TestManager &testManager = anna::testing::TestManager::instantiate(); - - - return true; // OK -} - -bool EventOperation::test_id__waitfe_hex(std::string &response, unsigned int id, const std::string & hex, bool strict) { - - Launcher& my_app = static_cast (anna::app::functions::getApp()); - - + try { + testManager.getTestCase(id)->addCommand(script); // creates / reuses + response = "Done"; + } + catch(anna::RuntimeException &ex) { + ex.trace(); + response += "failed"; + return false; + } return true; // OK } -bool EventOperation::test_id__waitfc_hex(std::string &response, unsigned int id, const std::string & hex, bool strict) { +bool EventOperation::test_id__waitfefc_hex(std::string &response, unsigned int id, bool fe_or_fc, const std::string & hex, bool strict) { Launcher& my_app = static_cast (anna::app::functions::getApp()); + anna::testing::TestManager &testManager = anna::testing::TestManager::instantiate(); + // Get DataBlock from hex content: + anna::DataBlock db_aux(true); + std::string hexString = hex; + hexString.erase(std::remove(hexString.begin(), hexString.end(), ':'), hexString.end()); + LOGDEBUG( + std::string msg = "Hex string (remove colons if exists): "; + msg += hexString; + anna::Logger::debug(msg, ANNA_FILE_LOCATION); + ); + + std::string regexp; + try { + anna::functions::fromHexString(hexString, db_aux); // could launch exception + regexp = anna::functions::asHexString(db_aux); + } + catch(anna::RuntimeException &ex) { + ex.trace(); + response += "failed"; + return false; + } + // optional 'full': + if(!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}"); - return true; // OK -} - -bool EventOperation::test_id__waitfe_msg(std::string &response, unsigned int id, const std::string & diameterJson, bool strict) { - - Launcher& my_app = static_cast (anna::app::functions::getApp()); - + regexp.insert(0, "^"); + regexp += "$"; + } + try { + testManager.getTestCase(id)->addWaitDiameterRegexpHex(fe_or_fc, regexp); + response = "Done"; + } + catch(anna::RuntimeException &ex) { + ex.trace(); + response += "failed"; + return false; + } return true; // OK } -bool EventOperation::test_id__waitfc_msg(std::string &response, unsigned int id, const std::string & diameterJson, bool strict) { +bool EventOperation::test_id__waitfefc_msg(std::string &response, unsigned int id, bool fe_or_fc, const std::string & diameterJson, bool strict) { Launcher& my_app = static_cast (anna::app::functions::getApp()); + anna::testing::TestManager &testManager = anna::testing::TestManager::instantiate(); + bool success; + std::string diameterXml = anna::json::functions::json2xml(diameterJson, success); + if (!success) { + response += "json to xml failed, unable to load message !"; + return false; + } + try { + anna::diameter::codec::Message codecMsg; // auxiliary codec message + codecMsg.loadXMLString(diameterXml); + 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(!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: + //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: + 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 += "$"; + } - return true; // OK -} - -bool EventOperation::test_id__waitfe(std::string &response, unsigned int id, const std::string & condition) { - - Launcher& my_app = static_cast (anna::app::functions::getApp()); - - + testManager.getTestCase(id)->addWaitDiameterRegexpXml(fe_or_fc, regexp); + response = "Done"; + } + catch(anna::RuntimeException &ex) { + ex.trace(); + response += "failed"; + return false; + } return true; // OK } -bool EventOperation::test_id__waitfc(std::string &response, unsigned int id, const std::string & condition) { +bool EventOperation::test_id__waitfefc(std::string &response, unsigned int id, bool fe_or_fc, + const std::string & code, + const std::string & bitR, + const std::string & hopByHop, + const std::string & applicationId, + const std::string & sessionId, + const std::string & resultCode, + const std::string & msisdn, + const std::string & imsi, + const std::string & serviceContextId) { Launcher& my_app = static_cast (anna::app::functions::getApp()); + anna::testing::TestManager &testManager = anna::testing::TestManager::instantiate(); - + try { // [code]|[bitR]|[hopByHop]|[applicationId]|[sessionId]|[resultCode]|[msisdn]|[imsi]|[serviceContextId] + testManager.getTestCase(id)->addWaitDiameter(fe_or_fc, code, bitR, hopByHop, applicationId, sessionId, resultCode, msisdn, imsi, serviceContextId); + response = "Done"; + } + catch(anna::RuntimeException &ex) { + ex.trace(); + response += "failed"; + return false; + } return true; // OK } @@ -814,8 +974,21 @@ bool EventOperation::test__finished(std::string &response) { bool EventOperation::test__clear(std::string &response) { Launcher& my_app = static_cast (anna::app::functions::getApp()); + anna::testing::TestManager &testManager = anna::testing::TestManager::instantiate(); - + try { + if (testManager.clearPool()) { + response = "All the programmed test cases have been dropped"; + } + else { + response = "There are not programmed test cases to be removed"; + } + } + catch(anna::RuntimeException &ex) { + ex.trace(); + response += "failed"; + return false; + } return true; // OK } diff --git a/example/diameter/launcher/EventOperation.hpp b/example/diameter/launcher/EventOperation.hpp index be117cf..6fceb85 100644 --- a/example/diameter/launcher/EventOperation.hpp +++ b/example/diameter/launcher/EventOperation.hpp @@ -110,16 +110,21 @@ public: bool test_id__description(std::string &response, unsigned int id, const std::string & description); bool test_id__ip_limit(std::string &response, unsigned int id, int amount = 1); bool test_id__timeout(std::string &response, unsigned int id, int msecs); - bool test_id__sendmsg2e(std::string &response, unsigned int id, const std::string & diameterJson, int stepNumber = -1); - bool test_id__sendmsg2c(std::string &response, unsigned int id, const std::string & diameterJson, int stepNumber = -1); + bool test_id__sendmsg2e_2c(std::string &response, unsigned int id, bool _2e_or_2c, const std::string & diameterJson, int stepNumber = -1); bool test_id__delay(std::string &response, unsigned int id, int msecs); bool test_id__sh_command(std::string &response, unsigned int id, const std::string & script); - bool test_id__waitfe_hex(std::string &response, unsigned int id, const std::string & hex, bool strict = false); - bool test_id__waitfc_hex(std::string &response, unsigned int id, const std::string & hex, bool strict = false); - bool test_id__waitfe_msg(std::string &response, unsigned int id, const std::string & diameterJson, bool strict = false); - bool test_id__waitfc_msg(std::string &response, unsigned int id, const std::string & diameterJson, bool strict = false); - bool test_id__waitfe(std::string &response, unsigned int id, const std::string & condition); - bool test_id__waitfc(std::string &response, unsigned int id, const std::string & condition); + bool test_id__waitfefc_hex(std::string &response, unsigned int id, bool fe_or_fc, const std::string & hex, bool strict = false); + bool test_id__waitfefc_msg(std::string &response, unsigned int id, bool fe_or_fc, const std::string & diameterJson, bool strict = false); + bool test_id__waitfefc(std::string &response, unsigned int id, bool fe_or_fc, + const std::string & code, + const std::string & bitR, + const std::string & hopByHop, + const std::string & applicationId, + const std::string & sessionId, + const std::string & resultCode, + const std::string & msisdn, + const std::string & imsi, + const std::string & serviceContextId); // Testcases execution // test__ diff --git a/example/diameter/launcher/Launcher.hpp b/example/diameter/launcher/Launcher.hpp index c8f34e6..4a7f392 100644 --- a/example/diameter/launcher/Launcher.hpp +++ b/example/diameter/launcher/Launcher.hpp @@ -75,7 +75,6 @@ class Launcher : public anna::comm::Application { std::string getSignalUSR2OutputFile() const throw(); void servicesFromXML(const anna::xml::Node* servicesNode, bool bindResources) throw(anna::RuntimeException); - anna::Millisecond checkTimeMeasure(const std::string ¶meter, const std::string &value) throw(anna::RuntimeException); void initialize() throw(anna::RuntimeException); // HTTP void run() throw(anna::RuntimeException); @@ -85,6 +84,8 @@ public: Launcher(); //~Launcher(); TODO + anna::Millisecond checkTimeMeasure(const std::string ¶meter, const std::string &value) throw(anna::RuntimeException); + void loadServicesFromFile(const std::string & xmlPathFile, bool bindResources) throw(anna::RuntimeException); void loadServicesFromXMLString(const std::string & xmlString, bool bindResources) throw(anna::RuntimeException); void startServices() throw(anna::RuntimeException); diff --git a/example/diameter/launcher/MyHandler.cpp b/example/diameter/launcher/MyHandler.cpp index 49205ed..7d312ef 100644 --- a/example/diameter/launcher/MyHandler.cpp +++ b/example/diameter/launcher/MyHandler.cpp @@ -158,7 +158,7 @@ bool MyHandler::doPOST(const std::string &uri, const nlohmann::json &j, std::str // Node management if (opType == "/node") { auto it = j.find("name"); - if (it != j.end()) + if (it != j.end() && it->is_string()) result = eop.node(response, *it); else response += "missing 'name' string field"; @@ -170,21 +170,21 @@ bool MyHandler::doPOST(const std::string &uri, const nlohmann::json &j, std::str // Parsing operations else if (opType == "/code") { auto it = j.find("diameterJson"); - if (it != j.end()) + if (it != j.end() && it->is_object()) result = eop.code(response, it->dump(4)); // get the object as string (always indentation = 4) else response += "missing 'diameterJson' object field"; } else if (opType == "/decode") { auto it = j.find("diameterHex"); - if (it != j.end()) + if (it != j.end() && it->is_string()) result = eop.decode(response, *it); else response += "missing 'diameterHex' string field"; } else if (opType == "/loadmsg") { auto it = j.find("diameterJson"); - if (it != j.end()) + if (it != j.end() && it->is_object()) result = eop.loadmsg(response, it->dump(4)); // get the object as string (always indentation = 4) else response += "missing 'diameterJson' object field"; @@ -193,7 +193,7 @@ bool MyHandler::doPOST(const std::string &uri, const nlohmann::json &j, std::str // Hot changes else if (opType == "/services") { auto it = j.find("servicesJson"); - if (it != j.end()) { + if (it != j.end() && it->is_object()) { result = eop.services(response, it->dump(4)); // get the object as string (always indentation = 4) } else @@ -201,28 +201,28 @@ bool MyHandler::doPOST(const std::string &uri, const nlohmann::json &j, std::str } else if (opType == "/diameterServerSessions") { auto it = j.find("sessions"); - if (it != j.end()) + if (it != j.end() && it->is_number_integer()) result = eop.diameterServerSessions(response, it->get()); else response += "missing 'session' integer field"; } else if (opType == "/change-dir") { auto it = j.find("directory"); - std::string directory = (it != j.end()) ? *it : ""; // default is: restore initial directory + std::string directory = (it != j.end() && it->is_string()) ? *it : ""; // default is: restore initial directory result = eop.change_dir(response, directory); } // Client sessions visibility else if (opType == "/visibility") { auto it = j.find("action"); - if (it != j.end()) { + if (it != j.end() && it->is_string()) { std::string action = *it; it = j.find("addressPort"); - std::string addressPort = (it != j.end()) ? *it : ""; + std::string addressPort = (it != j.end() && it->is_string()) ? *it : ""; it = j.find("socket"); - int socket = (it != j.end()) ? it->get() : -1; + int socket = (it != j.end() && it->is_number_integer()) ? it->get() : -1; result = eop.visibility(response, action, addressPort, socket); } @@ -236,7 +236,7 @@ bool MyHandler::doPOST(const std::string &uri, const nlohmann::json &j, std::str } else if (opType == "/context") { auto it = j.find("targetFile"); - std::string targetFile = (it != j.end()) ? *it : ""; + std::string targetFile = (it != j.end() && it->is_string()) ? *it : ""; result = eop.context(response, targetFile); } else if (opType == "/forceCountersRecord") { @@ -244,16 +244,14 @@ bool MyHandler::doPOST(const std::string &uri, const nlohmann::json &j, std::str } else if (opType == "/log-statistics-samples") { auto it = j.find("list"); - if (it != j.end()) - result = eop.log_statistics_samples(response, *it); - else - response += "missing 'list' string field"; + std::string list = (it != j.end() && it->is_string()) ? *it : "list"; + result = eop.log_statistics_samples(response, list); } // Flow operations else if ((opType == "/sendmsg2e")||(opType == "/sendmsg2c")) { auto itJ = j.find("diameterJson"); - if (itJ != j.end()) { + if (itJ != j.end() && itJ->is_object()) { if (opType == "/sendmsg2e") result = eop.sendmsg_hex_2e(response, itJ->dump(4), true); // get the object as string (always indentation = 4) else @@ -264,7 +262,7 @@ bool MyHandler::doPOST(const std::string &uri, const nlohmann::json &j, std::str } else if ((opType == "/sendhex2e")||(opType == "/sendhex2c")) { auto itH = j.find("diameterHex"); - if (itH != j.end()) + if (itH != j.end() && itH->is_string()) if (opType == "/sendhex2e") result = eop.sendmsg_hex_2e(response, *itH, false); else @@ -275,8 +273,8 @@ bool MyHandler::doPOST(const std::string &uri, const nlohmann::json &j, std::str else if ((opType == "/answermsg2e")||(opType == "/answermsg2c")) { auto itJ = j.find("diameterJson"); auto itA = j.find("action"); - bool hasJ = (itJ != j.end()); - bool hasA = (itA != j.end()); + bool hasJ = (itJ != j.end() && itJ->is_object()); + bool hasA = (itA != j.end() && itA->is_string()); if (hasJ != hasA) { // XOR std::string action; @@ -298,85 +296,103 @@ bool MyHandler::doPOST(const std::string &uri, const nlohmann::json &j, std::str // test_id__ else if (opType == "/testid-description") { auto it = j.find("description"); - if (it != j.end()) + if (it != j.end() && it->is_string()) result = eop.test_id__description(response, atoi(param1.c_str()), *it); else response += "missing 'description' string field"; } else if (opType == "/testid-ip-limit") { auto it = j.find("amount"); - int amount = (it != j.end()) ? it->get() : 1; + int amount = (it != j.end() && it->is_number_integer()) ? it->get() : 1; result = eop.test_id__ip_limit(response, atoi(param1.c_str()), amount); } else if (opType == "/testid-timeout") { auto it = j.find("msecs"); - if (it != j.end()) + if (it != j.end() && it->is_number_integer()) result = eop.test_id__timeout(response, atoi(param1.c_str()), it->get()); else response += "missing 'msecs' integer field"; } else if ((opType == "/testid-sendmsg2e")||(opType == "/testid-sendmsg2c")) { auto it = j.find("diameterJson"); - if (it != j.end()) { + if (it != j.end() && it->is_object()) { auto itS = j.find("stepNumber"); - int stepNumber = (itS != j.end()) ? itS->get() : -1; + int stepNumber = (itS != j.end() && itS->is_number_integer()) ? itS->get() : -1; - if (opType == "/testid-sendmsg2e") - result = eop.test_id__sendmsg2e(response, atoi(param1.c_str()), it->dump(4), stepNumber); // get the object as string (always indentation = 4) - else - result = eop.test_id__sendmsg2c(response, atoi(param1.c_str()), it->dump(4), stepNumber); // get the object as string (always indentation = 4) + result = eop.test_id__sendmsg2e_2c(response, atoi(param1.c_str()), + (opType == "/testid-sendmsg2e"), it->dump(4), stepNumber); // get the object as string (always indentation = 4) } else response += "missing 'diameterJson' object field"; } else if (opType == "/testid-delay") { auto it = j.find("msecs"); - if (it != j.end()) + if (it != j.end() && it->is_number_integer()) result = eop.test_id__delay(response, atoi(param1.c_str()), it->get()); else response += "missing 'msecs' integer field"; } else if (opType == "/testid-sh-command") { auto it = j.find("script"); - if (it != j.end()) + if (it != j.end() && it->is_string()) result = eop.test_id__sh_command(response, atoi(param1.c_str()), *it); else response += "missing 'script' string field"; } else if ((opType == "/testid-waitfe-hex")||(opType == "/testid-waitfc-hex")) { auto it = j.find("hex"); - if (it != j.end()) { + if (it != j.end() && it->is_string()) { auto itS = j.find("strict"); - bool strict = (itS != j.end()) ? (*itS == "true") : false; + bool strict = (itS != j.end() && itS->is_string()) ? (*itS == "true") : false; - if (opType == "/testid-waitfe-hex") - result = eop.test_id__waitfe_hex(response, atoi(param1.c_str()), *it, strict); - else - result = eop.test_id__waitfc_hex(response, atoi(param1.c_str()), *it, strict); + result = eop.test_id__waitfefc_hex(response, atoi(param1.c_str()), (opType == "/testid-waitfe-hex"), *it, strict); } else response += "missing 'hex' string field"; } else if ((opType == "/testid-waitfe-msg")||(opType == "/testid-waitfc-msg")) { auto it = j.find("diameterJson"); - if (it != j.end()) { + if (it != j.end() && it->is_object()) { auto itS = j.find("strict"); - bool strict = (itS != j.end()) ? (*itS == "true") : false; + bool strict = (itS != j.end() && itS->is_string()) ? (*itS == "true") : false; - if (opType == "/testid-waitfe-msg") - result = eop.test_id__waitfe_msg(response, atoi(param1.c_str()), it->dump(4), strict); // get the object as string (always indentation = 4) - else - result = eop.test_id__waitfc_msg(response, atoi(param1.c_str()), it->dump(4), strict); // get the object as string (always indentation = 4) + result = eop.test_id__waitfefc_msg(response, atoi(param1.c_str()), (opType == "/testid-waitfe-msg"), it->dump(4), strict); // get the object as string (always indentation = 4) } else response += "missing 'diameterJson' object field"; } else if ((opType == "/testid-waitfe")||(opType == "/testid-waitfc")) { auto it = j.find("condition"); - if (it != j.end()) { + if (it != j.end() && it->is_object()) { + +/* + auto j2 = it->get(); + + // [code]|[bitR]|[hopByHop]|[applicationId]|[sessionId]|[resultCode]|[msisdn]|[imsi]|[serviceContextId] + auto it_code = j2.find("code"); + auto it_bitR = j2.find("bitR"); + auto it_hopByHop = j2.find("hopByHop"); + auto it_applicationId = j2.find("applicationId"); + auto it_sessionId = j2.find("sessionId"); + auto it_resultCode = j2.find("resultCode"); + auto it_msisdn = j2.find("msisdn"); + auto it_imsi = j2.find("imsi"); + auto it_serviceContextId = j2.find("serviceContextId"); + + std::string p1 = (it_code != j2.end() && it_code->is_string()) ? *it_code : ""; + std::string p2 = (it_bitR != j2.end() && it_bitR->is_string()) ? *it_bitR : ""; + std::string p3 = (it_hopByHop != it->end() && it_hopByHop->is_string()) ? *it_hopByHop : ""; + std::string p4 = (it_applicationId != it->end() && it_applicationId->is_string()) ? *it_applicationId : ""; + std::string p5 = (it_sessionId != it->end() && it_sessionId->is_string()) ? *it_sessionId : ""; + std::string p6 = (it_resultCode != it->end() && it_resultCode->is_string()) ? *it_resultCode : ""; + std::string p7 = (it_msisdn != it->end() && it_msisdn->is_string()) ? *it_msisdn : ""; + std::string p8 = (it_imsi != it->end() && it_imsi->is_string()) ? *it_imsi : ""; + std::string p9 = (it_serviceContextId != it->end() && it_serviceContextId->is_string()) ? *it_serviceContextId : ""; +*/ + // [code]|[bitR]|[hopByHop]|[applicationId]|[sessionId]|[resultCode]|[msisdn]|[imsi]|[serviceContextId] auto it_code = it->find("code"); auto it_bitR = it->find("bitR"); @@ -388,21 +404,17 @@ bool MyHandler::doPOST(const std::string &uri, const nlohmann::json &j, std::str auto it_imsi = it->find("imsi"); auto it_serviceContextId = it->find("serviceContextId"); - std::string condition; - condition += (it_code != it->end()) ? *it_code : ""; condition += "|"; - condition += (it_bitR != it->end()) ? *it_bitR : ""; condition += "|"; - condition += (it_hopByHop != it->end()) ? *it_hopByHop : ""; condition += "|"; - condition += (it_applicationId != it->end()) ? *it_applicationId : ""; condition += "|"; - condition += (it_sessionId != it->end()) ? *it_sessionId : ""; condition += "|"; - condition += (it_resultCode != it->end()) ? *it_resultCode : ""; condition += "|"; - condition += (it_msisdn != it->end()) ? *it_msisdn : ""; condition += "|"; - condition += (it_imsi != it->end()) ? *it_imsi : ""; condition += "|"; - condition += (it_serviceContextId != it->end()) ? *it_serviceContextId : ""; - - if (opType == "/testid-waitfe") - result = eop.test_id__waitfe(response, atoi(param1.c_str()), condition); - else - result = eop.test_id__waitfc(response, atoi(param1.c_str()), condition); + std::string p1 = (it_code != it->end() && it_code->is_string()) ? *it_code : ""; + std::string p2 = (it_bitR != it->end() && it_bitR->is_string()) ? *it_bitR : ""; + std::string p3 = (it_hopByHop != it->end() && it_hopByHop->is_string()) ? *it_hopByHop : ""; + std::string p4 = (it_applicationId != it->end() && it_applicationId->is_string()) ? *it_applicationId : ""; + std::string p5 = (it_sessionId != it->end() && it_sessionId->is_string()) ? *it_sessionId : ""; + std::string p6 = (it_resultCode != it->end() && it_resultCode->is_string()) ? *it_resultCode : ""; + std::string p7 = (it_msisdn != it->end() && it_msisdn->is_string()) ? *it_msisdn : ""; + std::string p8 = (it_imsi != it->end() && it_imsi->is_string()) ? *it_imsi : ""; + std::string p9 = (it_serviceContextId != it->end() && it_serviceContextId->is_string()) ? *it_serviceContextId : ""; + + result = eop.test_id__waitfefc(response, atoi(param1.c_str()), (opType == "/testid-waitfe"), p1, p2, p3, p4, p5, p6, p7, p8, p9); } else response += "missing 'condition' object field"; @@ -412,51 +424,51 @@ bool MyHandler::doPOST(const std::string &uri, const nlohmann::json &j, std::str // test__ else if (opType == "/test-ttps") { auto it = j.find("amount"); - if (it != j.end()) + if (it != j.end() && it->is_number_integer()) result = eop.test__ttps(response, it->get()); else response += "missing 'amount' integer field"; } else if (opType == "/test-next") { auto it = j.find("syncAmount"); - int syncAmount = (it != j.end()) ? it->get() : 1; + int syncAmount = (it != j.end() && it->is_number_integer()) ? it->get() : 1; result = eop.test__next(response, syncAmount); } else if (opType == "/test-ip-limit") { auto it = j.find("amount"); - int amount = (it != j.end()) ? it->get() : -2; // default is: show current ip-limit and in-progress test cases amount + int amount = (it != j.end() && it->is_number_integer()) ? it->get() : -2; // default is: show current ip-limit and in-progress test cases amount result = eop.test__ip_limit(response, amount); } else if (opType == "/test-goto") { auto it = j.find("id"); - if (it != j.end()) + if (it != j.end() && it->is_number_integer()) result = eop.test__goto(response, it->get()); else response += "missing 'id' integer field"; } else if (opType == "/test-run") { auto it = j.find("id"); - if (it != j.end()) + if (it != j.end() && it->is_number_integer()) result = eop.test__run(response, it->get()); else response += "missing 'id' integer field"; } else if (opType == "/test-look") { auto it = j.find("id"); - int id = (it != j.end()) ? it->get() : -1; // default is: current + int id = (it != j.end() && it->is_number_integer()) ? it->get() : -1; // default is: current result = eop.test__look(response, id); } else if (opType == "/test-state") { auto it = j.find("id"); - int id = (it != j.end()) ? it->get() : -1; // default is: current + int id = (it != j.end() && it->is_number_integer()) ? it->get() : -1; // default is: current result = eop.test__state(response, id); } else if (opType == "/test-interact") { auto it = j.find("amount"); - if (it != j.end()) { + if (it != j.end() && it->is_number_integer()) { auto itI = j.find("id"); - int id = (itI != j.end()) ? itI->get() : -1; // default is: current + int id = (itI != j.end() && itI->is_number_integer()) ? itI->get() : -1; // default is: current result = eop.test__interact(response, it->get(), id); } @@ -465,10 +477,10 @@ bool MyHandler::doPOST(const std::string &uri, const nlohmann::json &j, std::str } else if (opType == "/test-reset") { auto it = j.find("type"); - if (it != j.end()) { + if (it != j.end() && it->is_string()) { auto itI = j.find("id"); - int id = (itI != j.end()) ? itI->get() : -2; // default is: apply to all the tests + int id = (itI != j.end() && itI->is_number_integer()) ? itI->get() : -2; // default is: apply to all the tests if ((*it == "soft") || (*it == "hard")) { result = eop.test__reset(response, (*it == "soft"), id); @@ -481,14 +493,14 @@ bool MyHandler::doPOST(const std::string &uri, const nlohmann::json &j, std::str } else if (opType == "/test-repeats") { auto it = j.find("amount"); - if (it != j.end()) + if (it != j.end() && it->is_number_integer()) result = eop.test__repeats(response, it->get()); else response += "missing 'amount' integer field"; } else if (opType == "/test-auto-reset") { auto it = j.find("type"); - if (it != j.end()) { + if (it != j.end() && it->is_string()) { if ((*it == "soft") || (*it == "hard")) { result = eop.test__auto_reset(response, (*it == "soft")); @@ -510,8 +522,10 @@ bool MyHandler::doPOST(const std::string &uri, const nlohmann::json &j, std::str } else if (opType == "/test-junit") { auto it = j.find("targetFile"); - std::string targetFile = (it != j.end()) ? *it : ""; // default is: get junit on response instead dumping on file - result = eop.test__junit(response, targetFile); + if (it != j.end() && it->is_string()) + result = eop.test__junit(response, *it); + else + response += "missing 'targetFile' string field"; } else if (opType == "/test-summary-counts") { result = eop.test__summary_counts(response); @@ -524,10 +538,10 @@ bool MyHandler::doPOST(const std::string &uri, const nlohmann::json &j, std::str } else if (opType == "/test-report") { auto it = j.find("state"); - std::string state = (it != j.end()) ? *it : "all"; // initialized|in-progress|failed|success|[all]|none + std::string state = (it != j.end() && it->is_string()) ? *it : "all"; // initialized|in-progress|failed|success|[all]|none auto itA = j.find("action"); - std::string action = (itA != j.end()) ? *itA : "enable"; // default is: enable + std::string action = (itA != j.end() && itA->is_string()) ? *itA : "enable"; // default is: enable if ((action == "enable") || (action == "disable")) { result = eop.test__report(response, state, (action == "enable")); @@ -538,7 +552,7 @@ bool MyHandler::doPOST(const std::string &uri, const nlohmann::json &j, std::str else if ((opType == "/test-report-hex")||(opType == "/test-dump_stdout")) { auto itA = j.find("action"); - std::string action = (itA != j.end()) ? *itA : "enable"; // default is: enable + std::string action = (itA != j.end() && itA->is_string()) ? *itA : "enable"; // default is: enable if ((action == "enable") || (action == "disable")) { bool enable = (action == "enable"); diff --git a/example/diameter/launcher/resources/HELP.md b/example/diameter/launcher/resources/HELP.md index fec3b72..bef7e3f 100644 --- a/example/diameter/launcher/resources/HELP.md +++ b/example/diameter/launcher/resources/HELP.md @@ -960,7 +960,7 @@ Updates diameter server sessions to be accepted. ``` { - "sessions": + "sessions": } ``` @@ -1004,7 +1004,7 @@ Updates ADML working directory. { "action":"" [, "addressPort":""] - [, "socket":] + [, "socket":] } ``` @@ -1036,13 +1036,13 @@ Reset statistics and counters. #### POST /context -Dump ADML context at file path provided. If empty, default path is selected. Context information is not retrieved in the response, so, file is related to ADML execution context. +Dump ADML context at file path provided. If empty (or field missing), default path is selected. Context information is not retrieved in the response, so, file is related to ADML execution context. **Request body**: ``` { - "targetFile":"[file path]" + ["targetFile":"[file path]"] } ``` @@ -1078,7 +1078,7 @@ Set the statistics concepts to be logged. To know the concept indentifiers regis ``` { - "list":"" + ["list":""] } ``` @@ -1153,7 +1153,7 @@ or ``` { - "action":"" + "action":"[action: <[list]|dump|clear|exhaust|rotate>]" } ``` @@ -1184,7 +1184,7 @@ or ``` { - "action":"" + "action":"[action: <[list]|dump|clear|exhaust|rotate>]" } ``` @@ -1243,21 +1243,651 @@ Sends diameter expressed in hexadecimal string (no spaces, no colons, i.e.: `010 ADML implements a bulting *Finite State Machine* to plan testing flows with a great flexibility. -#### POST /xxxxxxxx +#### POST /testid-description -Referred files (*dictionaries, cer, cea, etc.*) shall be accesible for ADML and are not provided in this operation. +**Request body**: + +``` +{ + "description":"" +} +``` + +**Response body**: + +``` +{ + "result":"", + "response":"" +} +``` + +#### POST /testid-ip-limit + +In-Progress limit is the maximum number of tests which can be executed in parallel. +This operation allows a specific test to set this global pool behaviour. + +**Request body**: + +``` +{ + "amount":[amount (integer, 1 by default: execution in sequence)] +} +``` + +**Response body**: + +``` +{ + "result":"", + "response":"" +} +``` + +#### POST /testid-timeout + +**Request body**: + +``` +{ + "msecs": +} +``` + +**Response body**: + +``` +{ + "result":"", + "response":"" +} +``` + +#### POST /testid-sendmsg2e + +**Request body**: + +``` +{ + "diameterJson": + [,"stepNumber":[amount (integer, -1 no step associated)]] +} +``` + +**Response body**: + +``` +{ + "result":"", + "response":"" +} +``` + +#### POST /testid-sendmsg2c + +**Request body**: + +``` +{ + "diameterJson": + [,"stepNumber":[amount (integer, -1 no step associated)]] +} +``` + +**Response body**: + +``` +{ + "result":"", + "response":"" +} +``` + +#### POST /testid-delay + +**Request body**: + +``` +{ + "msecs": +} +``` + +**Response body**: + +``` +{ + "result":"", + "response":"" +} +``` + +#### POST /testid-sh-command + +**Request body**: + +``` +{ + "script":"