diff --git a/src/v2i-hub/TelematicBridgePlugin/CMakeLists.txt b/src/v2i-hub/TelematicBridgePlugin/CMakeLists.txt index 6e0a0e260..df7b1c0f7 100644 --- a/src/v2i-hub/TelematicBridgePlugin/CMakeLists.txt +++ b/src/v2i-hub/TelematicBridgePlugin/CMakeLists.txt @@ -8,8 +8,10 @@ TARGET_LINK_LIBRARIES ( ${PROJECT_NAME} tmxutils jsoncpp nats) #################################################### ################## Testing ####################### #################################################### +add_library(${PROJECT_NAME}_lib src/TelematicUnit.cpp) +target_link_libraries(${PROJECT_NAME}_lib PUBLIC tmxutils jsoncpp nats) enable_testing() include_directories(${PROJECT_SOURCE_DIR}/src) file(GLOB_RECURSE TEST_SOURCES LIST_DIRECTORIES false test/*.h test/*.cpp) add_executable(${PROJECT_NAME}_test ${TEST_SOURCES}) -target_link_libraries(${PROJECT_NAME}_test PRIVATE gtest tmxutils jsoncpp nats) \ No newline at end of file +target_link_libraries(${PROJECT_NAME}_test PRIVATE gtest ${PROJECT_NAME}_lib) \ No newline at end of file diff --git a/src/v2i-hub/TelematicBridgePlugin/src/TelematicUnit.cpp b/src/v2i-hub/TelematicBridgePlugin/src/TelematicUnit.cpp index 49a471ff1..29a026570 100644 --- a/src/v2i-hub/TelematicBridgePlugin/src/TelematicUnit.cpp +++ b/src/v2i-hub/TelematicBridgePlugin/src/TelematicUnit.cpp @@ -19,7 +19,7 @@ namespace TelematicBridge void TelematicUnit::registerUnitRequestor() { // Reset registration status - setRegistered(false); + _isRegistered = false; while (!_isRegistered) { @@ -39,13 +39,13 @@ namespace TelematicBridge _eventName = root[EVENT_NAME].asString(); // Unit is registered when server responds with event information (location, testing_type, event_name) - setRegistered(true); + _isRegistered = true; } natsMsg_Destroy(reply); } else { - PLOG(logERROR) << "NATS regsiter Error: " << s << "-" << natsStatus_GetText(s); + throw TelematicBridgeException(natsStatus_GetText(s)); } sleep(1); } @@ -66,7 +66,7 @@ namespace TelematicBridge PLOG(logDEBUG2) << "Inside available topic replier"; stringstream topic; topic << _unit.unitId << AVAILABLE_TOPICS; - auto s = natsConnection_Subscribe(&_subAvailableTopic, _conn, topic.str().c_str(), onAvailableTopicsCallback, this); + natsConnection_Subscribe(&_subAvailableTopic, _conn, topic.str().c_str(), onAvailableTopicsCallback, this); } } @@ -77,7 +77,7 @@ namespace TelematicBridge PLOG(logDEBUG2) << "Inside selected topic replier"; stringstream topic; topic << _unit.unitId << PUBLISH_TOPICS; - auto s = natsConnection_Subscribe(&_subSelectedTopic, _conn, topic.str().c_str(), onSelectedTopicsCallback, this); + natsConnection_Subscribe(&_subSelectedTopic, _conn, topic.str().c_str(), onSelectedTopicsCallback, this); } } @@ -88,7 +88,7 @@ namespace TelematicBridge PLOG(logDEBUG2) << "Inside check status replier"; stringstream topic; topic << _unit.unitId << CHECK_STATUS; - auto s = natsConnection_Subscribe(&_subCheckStatus, _conn, topic.str().c_str(), onCheckStatusCallback, this); + natsConnection_Subscribe(&_subCheckStatus, _conn, topic.str().c_str(), onCheckStatusCallback, this); } } @@ -113,10 +113,13 @@ namespace TelematicBridge // Sends a reply if (natsMsg_GetReply(msg) != nullptr) { - TelematicUnit *obj = (TelematicUnit *)object; - auto reply = constructAvailableTopicsReplyString(obj->_unit, obj->_availableTopics, obj->_excludedTopics); - PLOG(logDEBUG3) << "Available topics replied! " << reply; - natsConnection_PublishString(nc, natsMsg_GetReply(msg), reply.c_str()); + const auto obj = (TelematicUnit *)object; + if (obj) + { + auto reply = constructAvailableTopicsReplyString(obj->_unit, obj->_availableTopics, obj->_excludedTopics); + PLOG(logDEBUG3) << "Available topics replied! " << reply; + natsConnection_PublishString(nc, natsMsg_GetReply(msg), reply.c_str()); + } natsMsg_Destroy(msg); } } @@ -131,7 +134,7 @@ namespace TelematicBridge auto root = parseJson(msgStr); if (root.isMember(TOPICS) && root[TOPICS].isArray()) { - TelematicUnit *obj = (TelematicUnit *)object; + auto obj = (TelematicUnit *)object; // clear old selected topics obj->_selectedTopics.clear(); @@ -144,8 +147,8 @@ namespace TelematicBridge string reply = "request received!"; PLOG(logDEBUG3) << "Selected topics replied: " << reply; natsConnection_PublishString(nc, natsMsg_GetReply(msg), reply.c_str()); + natsMsg_Destroy(msg); } - natsMsg_Destroy(msg); } void TelematicUnit::onCheckStatusCallback(natsConnection *nc, natsSubscription *sub, natsMsg *msg, void *object) @@ -160,20 +163,21 @@ namespace TelematicBridge } } - string TelematicUnit::constructPublishedDataString(const unit_st &unit, const string &_eventLocation, const string &_testingType, const string &_eventName, const string &topicName, const Json::Value payload) + string TelematicUnit::constructPublishedDataString(const unit_st &unit, const string &eventLocation, const string &testingType, const string &eventName, const string &topicName, const Json::Value& payload) const { Json::Value message; message[UNIT_ID] = unit.unitId; message[UNIT_NAME] = unit.unitName; message[UNIT_TYPE] = unit.unitType; - message[LOCATION] = _eventLocation; - message[TESTING_TYPE] = _testingType; - message[EVENT_NAME] = _eventName; + message[LOCATION] = eventLocation; + message[TESTING_TYPE] = testingType; + message[EVENT_NAME] = eventName; message[TOPIC_NAME] = topicName; - message[TIMESTAMP] = duration_cast(system_clock::now().time_since_epoch()).count(); + message[TIMESTAMP] = payload.isMember("timestamp") ? payload["timestamp"].asUInt64() : duration_cast(system_clock::now().time_since_epoch()).count(); message[PAYLOAD] = payload; Json::FastWriter fasterWirter; string jsonStr = fasterWirter.write(message); + return jsonStr; } Json::Value TelematicUnit::parseJson(const string &jsonStr) @@ -211,12 +215,7 @@ namespace TelematicBridge return reply; } - void TelematicUnit::setRegistered(bool isRegistered) - { - _isRegistered = isRegistered; - } - - void TelematicUnit::setUnit(unit_st unit) + void TelematicUnit::setUnit(const unit_st& unit) { lock_guard lock(_unitMutex); _unit = unit; diff --git a/src/v2i-hub/TelematicBridgePlugin/src/TelematicUnit.h b/src/v2i-hub/TelematicBridgePlugin/src/TelematicUnit.h index a69bde47d..4ed37b517 100644 --- a/src/v2i-hub/TelematicBridgePlugin/src/TelematicUnit.h +++ b/src/v2i-hub/TelematicBridgePlugin/src/TelematicUnit.h @@ -65,7 +65,7 @@ namespace TelematicBridge explicit TelematicUnit() = default; /** * @brief A function for telematic unit to connect to NATS server. Throw exception is connection failed. * - * @param const string NATS server URL + * @param string string NATS server URL */ void connect(const string &natsURL); @@ -77,7 +77,8 @@ namespace TelematicBridge void registerUnitRequestor(); /** - * @brief A NATS replier to publish available topics upon receiving a request for a list of available topics. + * @brief A NATS replier to subscribe to NATS server and receive available topics request. + * Publish list of available topics after receiving/processing the request. */ void availableTopicsReplier(); @@ -89,7 +90,8 @@ namespace TelematicBridge void selectedTopicsReplier(); /** - * @brief A NATS replier to publish unit status upon receiving a request for status check from telematic server. + * @brief A NATS replier to subscribe to NATS server and receive request for status check from telematic server. + * Publish unit status upon receiving a request. */ void checkStatusReplier(); @@ -113,11 +115,6 @@ namespace TelematicBridge */ static string constructAvailableTopicsReplyString(const unit_st &unit, const vector &availableTopicList, const string &excludedTopics); - /** - * @brief Update isregisterd indicator - */ - void setRegistered(bool isRegistered); - /** * @brief A function to update available topics global variables when discovering a new topic. */ @@ -130,15 +127,15 @@ namespace TelematicBridge * @param string Testing type * @param string Event name * @param string Topic name is a combination of type_subtype_source from TMX IVPMessage - * @param string Payload is the actual data generated by V2xHub plugin + * @param Json::Value Payload is the actual data generated by V2xHub plugin */ - string constructPublishedDataString(const unit_st &unit, const string &_eventLocation, const string &_testingType, const string &_eventName, const string &topicName, const Json::Value payload); + string constructPublishedDataString(const unit_st &unit, const string &eventLocation, const string &testingType, const string &eventName, const string &topicName, const Json::Value& payload) const; /** * @brief A function to update global unit variable * @param unit_st object that has the unit id, type and name information */ - void setUnit(unit_st unit); + void setUnit(const unit_st& unit); /** * @brief A function to update excluded topics. @@ -153,8 +150,19 @@ namespace TelematicBridge */ bool inSelectedTopics(const string &topic); + /** + * @brief A callback function for available topic replier + */ static void onAvailableTopicsCallback(natsConnection *nc, natsSubscription *sub, natsMsg *msg, void *object); + + /** + * @brief A callback function for selected topic replier + */ static void onSelectedTopicsCallback(natsConnection *nc, natsSubscription *sub, natsMsg *msg, void *object); + + /** + * @brief A callback function for check status replier + */ static void onCheckStatusCallback(natsConnection *nc, natsSubscription *sub, natsMsg *msg, void *object); ~TelematicUnit(); diff --git a/src/v2i-hub/TelematicBridgePlugin/test/test_TelematicUnit.cpp b/src/v2i-hub/TelematicBridgePlugin/test/test_TelematicUnit.cpp new file mode 100644 index 000000000..20708f336 --- /dev/null +++ b/src/v2i-hub/TelematicBridgePlugin/test/test_TelematicUnit.cpp @@ -0,0 +1,117 @@ +#include +#include "TelematicUnit.h" + +namespace TelematicBridge +{ + class test_TelematicUnit : public ::testing::Test + { + public: + shared_ptr _telematicUnitPtr = make_shared(); + unit_st unit = + { + "test_id", + "test_name", + "infrastructure"}; + }; + + TEST_F(test_TelematicUnit, setUnit) + { + ASSERT_NO_THROW(_telematicUnitPtr->setUnit(unit)); + } + + TEST_F(test_TelematicUnit, updateExcludedTopics) + { + ASSERT_NO_THROW(_telematicUnitPtr->updateExcludedTopics("test_topic")); + } + + TEST_F(test_TelematicUnit, inSelectedTopics) + { + ASSERT_FALSE(_telematicUnitPtr->inSelectedTopics("test_topic")); + } + + TEST_F(test_TelematicUnit, updateAvailableTopics) + { + ASSERT_NO_THROW(_telematicUnitPtr->updateAvailableTopics("test_topic")); + } + + TEST_F(test_TelematicUnit, constructAvailableTopicsReplyString) + { + vector topics = {"test_topic", "excluded_topic"}; + string excluded_topic = "excluded_topic"; + auto reply = TelematicUnit::constructAvailableTopicsReplyString(unit, topics, excluded_topic); + auto json = TelematicUnit::parseJson(reply); + ASSERT_EQ("test_topic", json["topics"][0]["name"].asString()); + } + + TEST_F(test_TelematicUnit, constructPublishedDataString) + { + string eventLocation = "location"; + string testingType = "unit_test"; + string eventName = "testing"; + string topicName = "test_topic"; + Json::Value payload; + payload["body"] = "test_body"; + auto reply = _telematicUnitPtr->constructPublishedDataString(unit, eventLocation, testingType, eventName, topicName, payload); + auto json = TelematicUnit::parseJson(reply); + ASSERT_EQ(eventLocation, json["location"].asString()); + ASSERT_EQ(testingType, json["testing_type"].asString()); + ASSERT_EQ(eventName, json["event_name"].asString()); + } + + TEST_F(test_TelematicUnit, onCheckStatusCallback) + { + natsMsg *msg; + string data = "{\"data\":\"test\"}"; + natsMsg_Create(&msg, "test_subject", "Test_reply", data.c_str(), data.size()); + ASSERT_NO_THROW(TelematicUnit::onCheckStatusCallback(nullptr, nullptr, msg, nullptr)); + } + + TEST_F(test_TelematicUnit, onSelectedTopicsCallback) + { + natsMsg *msg; + string data = "{\"data\":\"test\"}"; + natsMsg_Create(&msg, "test_subject", "Test_reply", data.c_str(), data.size()); + ASSERT_NO_THROW(TelematicUnit::onSelectedTopicsCallback(nullptr, nullptr, msg, nullptr)); + } + + TEST_F(test_TelematicUnit, onAvailableTopicsCallback) + { + natsMsg *msg; + string data = "{\"data\":\"test\"}"; + natsMsg_Create(&msg, "test_subject", "Test_reply", data.c_str(), data.size()); + ASSERT_NO_THROW(TelematicUnit::onAvailableTopicsCallback(nullptr, nullptr, msg, _telematicUnitPtr.get())); + } + + TEST_F(test_TelematicUnit, publishMessage) + { + string topicName = "test_topic"; + Json::Value payload; + payload["body"] = "test_body"; + ASSERT_THROW(_telematicUnitPtr->publishMessage(topicName, payload), TelematicBridgeException); + } + + TEST_F(test_TelematicUnit, checkStatusReplier) + { + _telematicUnitPtr->checkStatusReplier(); + } + + TEST_F(test_TelematicUnit, selectedTopicsReplier) + { + _telematicUnitPtr->selectedTopicsReplier(); + } + + TEST_F(test_TelematicUnit, availableTopicsReplier) + { + _telematicUnitPtr->availableTopicsReplier(); + } + + TEST_F(test_TelematicUnit, registerUnitRequestor) + { + ASSERT_THROW(_telematicUnitPtr->registerUnitRequestor(), TelematicBridgeException); + } + + TEST_F(test_TelematicUnit, connect) + { + ASSERT_THROW(_telematicUnitPtr->connect("nats://127.0.0.1:4222"), TelematicBridgeException); + } +} \ No newline at end of file