diff --git a/src/v2i-hub/RSUHealthMonitorPlugin/CMakeLists.txt b/src/v2i-hub/RSUHealthMonitorPlugin/CMakeLists.txt index d863a4bf1..2bbadf66a 100755 --- a/src/v2i-hub/RSUHealthMonitorPlugin/CMakeLists.txt +++ b/src/v2i-hub/RSUHealthMonitorPlugin/CMakeLists.txt @@ -13,7 +13,7 @@ TARGET_LINK_LIBRARIES(${PROJECT_NAME} PUBLIC tmxutils jsoncpp NemaTode) ############# enable_testing() include_directories(${PROJECT_SOURCE_DIR}/src) -add_library(${PROJECT_NAME}_lib src/RSUHealthMonitorWorker.cpp) +add_library(${PROJECT_NAME}_lib src/RSUHealthMonitorWorker.cpp src/RSUConfigurationList) target_link_libraries(${PROJECT_NAME}_lib PUBLIC tmxutils NemaTode diff --git a/src/v2i-hub/RSUHealthMonitorPlugin/manifest.json b/src/v2i-hub/RSUHealthMonitorPlugin/manifest.json index f2ee94443..c6e40ab8d 100755 --- a/src/v2i-hub/RSUHealthMonitorPlugin/manifest.json +++ b/src/v2i-hub/RSUHealthMonitorPlugin/manifest.json @@ -18,7 +18,7 @@ "description": "Sending RSU SNMP GET request at every configured interval. Default every 1 second. Unit of measure: second." }, { - "key":"RSUIp", + "key":"RSUIp",//RSUConfiguration ->RSUS "default":"192.168.XX.XX", "description":"An IP address of the RSU the V2X hub is connected to." }, @@ -33,17 +33,17 @@ "description":"SNMP v3 authentication passphrase" }, { - "key":"SecurityUser", + "key":"SecurityUser", // user "default":"authOnlyUser", "description":"SNMP Security Name" }, { - "key":"SecurityLevel", - "default":"authPriv", + "key":"SecurityLevel", + "default":"authPriv", //Make this constant "description":"SNMP Security level" }, { - "key":"RSUMIBVersion", + "key":"RSUMIBVersion",//mibVersion "default":"RSU4.1", "description":"The version of RSU MIB (Management Information Base). E.G. RSU4.1 or RSU1218. Currently only support RSU4.1" } diff --git a/src/v2i-hub/RSUHealthMonitorPlugin/src/RSUConfigurationException.h b/src/v2i-hub/RSUHealthMonitorPlugin/src/RSUConfigurationException.h new file mode 100644 index 000000000..7a7b5cf89 --- /dev/null +++ b/src/v2i-hub/RSUHealthMonitorPlugin/src/RSUConfigurationException.h @@ -0,0 +1,19 @@ +#pragma once +#include + +namespace RSUHealthMonitor +{ + class RSUConfigurationException : public std::exception + { + private: + std::string message; + + public: + RSUConfigurationException(const char *msg) : message(msg){}; + const char *what() + { + return message.c_str(); + } + }; + +} \ No newline at end of file diff --git a/src/v2i-hub/RSUHealthMonitorPlugin/src/RSUConfigurationList.cpp b/src/v2i-hub/RSUHealthMonitorPlugin/src/RSUConfigurationList.cpp new file mode 100644 index 000000000..5b417a097 --- /dev/null +++ b/src/v2i-hub/RSUHealthMonitorPlugin/src/RSUConfigurationList.cpp @@ -0,0 +1,84 @@ + +#include "RSUConfigurationList.h" + +namespace RSUHealthMonitor +{ + Json::Value RSUConfigurationList::parseJson(std::string rsuConfigsStr) + { + JSONCPP_STRING err; + Json::Value root; + auto length = static_cast(rsuConfigsStr.length()); + Json::CharReaderBuilder builder; + std::unique_ptr reader(builder.newCharReader()); + if (!reader->parse(rsuConfigsStr.c_str(), rsuConfigsStr.c_str() + length, &root, &err)) + { + std::stringstream oss; + oss << "Parse RSUs raw string error: "; + oss << err.c_str(); + throw RSUConfigurationException(oss.str().c_str()); + } + return root; + } + void RSUConfigurationList::parseRSUs(std::string rsuConfigsStr) + { + auto json = parseJson(rsuConfigsStr); + RSUConfiguration config; + auto rsuArray = json["RSUS"]; + if (!rsuArray.isArray()) + { + throw RSUConfigurationException("RSUS is not an array."); + } + for (auto i = 0; i != rsuArray.size(); i++) + { + if (rsuArray[i].isMember(RSUIpKey)) + { + config.rsuIp = rsuArray[i][RSUIpKey].asString(); + } + else + { + throw RSUConfigurationException("RSU IP does not exist."); + } + + if (rsuArray[i].isMember(SNMPPortKey)) + { + config.snmpPort = atoi(rsuArray[i][SNMPPortKey].asCString()); + } + else + { + throw RSUConfigurationException("SNMP port does not exist."); + } + + if (rsuArray[i].isMember(AuthPassPhraseKey)) + { + config.authPassPhrase = rsuArray[i][AuthPassPhraseKey].asString(); + } + else + { + throw RSUConfigurationException("Authentication pass phrase does not exist."); + } + + if (rsuArray[i].isMember(UserKey)) + { + config.user = rsuArray[i][UserKey].asString(); + } + else + { + throw RSUConfigurationException("User does not exist."); + } + + if (rsuArray[i].isMember(RSUMIBVersionKey)) + { + config.mibVersion = rsuArray[i][RSUMIBVersionKey].asString(); + } + else + { + throw RSUConfigurationException("RSU mib version does not exist."); + } + configs.push_back(config); + } + } + std::vector RSUConfigurationList::getConfigs() + { + return configs; + } +} \ No newline at end of file diff --git a/src/v2i-hub/RSUHealthMonitorPlugin/src/RSUConfigurationList.h b/src/v2i-hub/RSUHealthMonitorPlugin/src/RSUConfigurationList.h new file mode 100644 index 000000000..244ef731e --- /dev/null +++ b/src/v2i-hub/RSUHealthMonitorPlugin/src/RSUConfigurationList.h @@ -0,0 +1,56 @@ +#pragma once +#include +#include +#include +#include +#include "RSUConfigurationException.h" + +namespace RSUHealthMonitor +{ + static constexpr const char *RSUIpKey = "RSUIp"; + static constexpr const char *SNMPPortKey = "SNMPPort"; + static constexpr const char *UserKey = "User"; + static constexpr const char *AuthPassPhraseKey = "AuthPassPhrase"; + static constexpr const char *RSUMIBVersionKey = "RSUMIBVersion"; + static constexpr const char *SecurityLevelKey = "SecurityLevel"; + struct RSUConfiguration + { + std::string rsuIp; + uint16_t snmpPort; + std::string user; + std::string authPassPhrase; + std::string securityLevel = "authPriv"; + std::string mibVersion; + friend std::ostream &operator<<(std::ostream &os, const RSUConfiguration &config) + { + os << RSUIpKey << ": " << config.rsuIp << ", " << SNMPPortKey << ": " << config.snmpPort << ", " << UserKey << ": " << config.user << ", " << AuthPassPhraseKey << ": " << config.authPassPhrase << ", " << SecurityLevelKey << ": " << config.securityLevel << ", " << RSUMIBVersionKey << ": " << config.mibVersion; + return os; + } + }; + + class RSUConfigurationList + { + private: + std::vector configs; + /*** + * @brief Parse JSON string and return the corresponding JSON value. + * @param rsuConfigsStr A JSON string includes all RSUs related configrations. + * @return JSON::Value A JSON object that includes RSUS information. + */ + Json::Value parseJson(std::string rsuConfigsStr); + + public: + RSUConfigurationList() = default; + ~RSUConfigurationList() = default; + /** + * @brief Parse RSUs configrations in JSON string representation, and update the memeber of list of RSUConfiguration struct. + * @param rsuConfigsStr A JSON string includes all RSUs related configrations. + */ + void parseRSUs(std::string rsuConfigsStr); + /** + * @brief Get a list of RSUConfiguration struct. + */ + std::vector getConfigs(); + }; + +} // namespace RSUHealthMonitor diff --git a/src/v2i-hub/RSUHealthMonitorPlugin/test/test_RSUConfigurationList.cpp b/src/v2i-hub/RSUHealthMonitorPlugin/test/test_RSUConfigurationList.cpp new file mode 100644 index 000000000..5f8b919a2 --- /dev/null +++ b/src/v2i-hub/RSUHealthMonitorPlugin/test/test_RSUConfigurationList.cpp @@ -0,0 +1,65 @@ +#include +#include "RSUConfigurationList.h" + +namespace RSUHealthMonitor +{ + class test_RSUConfigurationList : public ::testing::Test + { + public: + std::shared_ptr rsuConfigList = std::make_shared(); + }; + + TEST_F(test_RSUConfigurationList, parseAndGetConfigs) + { + ASSERT_EQ(0, rsuConfigList->getConfigs().size()); + std::string rsuConfigsStr = "{ \"RSUS\": [ { \"RSUIp\": \"192.168.XX.XX\", \"SNMPPort\": \"161\", \"AuthPassPhrase\": \"dummy\", \"User\": \"authOnlyUser\", \"RSUMIBVersion\": \"RSU4.1\" },{ \"RSUIp\": \"192.168.00.XX\", \"SNMPPort\": \"162\", \"AuthPassPhrase\": \"tester\", \"User\": \"authPrivUser\", \"RSUMIBVersion\": \"RSU4.1\" }] }"; + rsuConfigList->parseRSUs(rsuConfigsStr); + ASSERT_EQ(2, rsuConfigList->getConfigs().size()); + } + TEST_F(test_RSUConfigurationList, parseAndGetConfigs_MalformatJSON) + { + ASSERT_EQ(0, rsuConfigList->getConfigs().size()); + std::string rsuConfigsStr = "{ \"RSUS { \"RSUIp\": \"192.168.XX.XX\", \"SNMPPort\": \"161\", \"AuthPassPhrase\": \"dummy\", \"User\": \"authOnlyUser\", \"RSUMIBVersion\": \"RSU4.1\" },{ \"RSUIp\": \"192.168.00.XX\", \"SNMPPort\": \"162\", \"AuthPassPhrase\": \"tester\", \"User\": \"authPrivUser\", \"RSUMIBVersion\": \"RSU4.1\" }] }"; + ASSERT_THROW(rsuConfigList->parseRSUs(rsuConfigsStr), RSUHealthMonitor::RSUConfigurationException); + ASSERT_EQ(0, rsuConfigList->getConfigs().size()); + } + + TEST_F(test_RSUConfigurationList, parseAndGetConfigs_missing_RSUS) + { + ASSERT_EQ(0, rsuConfigList->getConfigs().size()); + std::string rsuConfigsStr = "{ \"ERROR\": [ { \"RSUIp\": \"192.168.XX.XX\", \"SNMPPort\": \"161\", \"AuthPassPhrase\": \"dummy\", \"User\": \"authOnlyUser\", \"RSUMIBVersion\": \"RSU4.1\" },{ \"RSUIp\": \"192.168.00.XX\", \"SNMPPort\": \"162\", \"AuthPassPhrase\": \"tester\", \"User\": \"authPrivUser\", \"RSUMIBVersion\": \"RSU4.1\" }] }"; + ASSERT_THROW(rsuConfigList->parseRSUs(rsuConfigsStr), RSUHealthMonitor::RSUConfigurationException); + ASSERT_EQ(0, rsuConfigList->getConfigs().size()); + } + + TEST_F(test_RSUConfigurationList, parseAndGetConfigs_missing_SNMPPORT) + { + ASSERT_EQ(0, rsuConfigList->getConfigs().size()); + std::string rsuConfigsStr = "{ \"RSUS\": [ { \"RSUIp\": \"192.168.XX.XX\", \"SNMPPort_Missing\": \"161\", \"AuthPassPhrase\": \"dummy\", \"User\": \"authOnlyUser\", \"RSUMIBVersion\": \"RSU4.1\" },{ \"RSUIp\": \"192.168.00.XX\", \"SNMPPort\": \"162\", \"AuthPassPhrase\": \"tester\", \"User\": \"authPrivUser\", \"RSUMIBVersion\": \"RSU4.1\" }] }"; + ASSERT_THROW(rsuConfigList->parseRSUs(rsuConfigsStr), RSUHealthMonitor::RSUConfigurationException); + ASSERT_EQ(0, rsuConfigList->getConfigs().size()); + } + + TEST_F(test_RSUConfigurationList, parseAndGetConfigs_missing_AuthPassPhrase) + { + ASSERT_EQ(0, rsuConfigList->getConfigs().size()); + std::string rsuConfigsStr = "{ \"RSUS\": [ { \"RSUIp\": \"192.168.XX.XX\", \"SNMPPort\": \"161\", \"AuthPassPhrase_Missing\": \"dummy\", \"User\": \"authOnlyUser\", \"RSUMIBVersion\": \"RSU4.1\" },{ \"RSUIp\": \"192.168.00.XX\", \"SNMPPort\": \"162\", \"AuthPassPhrase\": \"tester\", \"User\": \"authPrivUser\", \"RSUMIBVersion\": \"RSU4.1\" }] }"; + ASSERT_THROW(rsuConfigList->parseRSUs(rsuConfigsStr), RSUHealthMonitor::RSUConfigurationException); + ASSERT_EQ(0, rsuConfigList->getConfigs().size()); + } + + TEST_F(test_RSUConfigurationList, parseAndGetConfigs_missing_User) + { + ASSERT_EQ(0, rsuConfigList->getConfigs().size()); + std::string rsuConfigsStr = "{ \"RSUS\": [ { \"RSUIp\": \"192.168.XX.XX\", \"SNMPPort\": \"161\", \"AuthPassPhrase\": \"dummy\", \"User_Missing\": \"authOnlyUser\", \"RSUMIBVersion\": \"RSU4.1\" },{ \"RSUIp\": \"192.168.00.XX\", \"SNMPPort\": \"162\", \"AuthPassPhrase\": \"tester\", \"User\": \"authPrivUser\", \"RSUMIBVersion\": \"RSU4.1\" }] }"; + ASSERT_THROW(rsuConfigList->parseRSUs(rsuConfigsStr), RSUHealthMonitor::RSUConfigurationException); + ASSERT_EQ(0, rsuConfigList->getConfigs().size()); + } + TEST_F(test_RSUConfigurationList, parseAndGetConfigs_missing_MibVersion) + { + ASSERT_EQ(0, rsuConfigList->getConfigs().size()); + std::string rsuConfigsStr = "{ \"RSUS\": [ { \"RSUIp\": \"192.168.XX.XX\", \"SNMPPort\": \"161\", \"AuthPassPhrase\": \"dummy\", \"User\": \"authOnlyUser\", \"RSUMIBVersion_Missing\": \"RSU4.1\" },{ \"RSUIp\": \"192.168.00.XX\", \"SNMPPort\": \"162\", \"AuthPassPhrase\": \"tester\", \"User\": \"authPrivUser\", \"RSUMIBVersion\": \"RSU4.1\" }] }"; + ASSERT_THROW(rsuConfigList->parseRSUs(rsuConfigsStr), RSUHealthMonitor::RSUConfigurationException); + ASSERT_EQ(0, rsuConfigList->getConfigs().size()); + } +} \ No newline at end of file