From 8c05d19b8be8392002af2dd6f7fe4c41dc7c5a9e Mon Sep 17 00:00:00 2001 From: "mergify[bot]" <37929162+mergify[bot]@users.noreply.github.com> Date: Tue, 28 May 2024 08:11:42 +0200 Subject: [PATCH] Use absolute paths when loading XML files (#4751) (#4829) MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit * Use absolute paths when loading XML files (#4751) * Refs #10173: Add XMLLoadFile unittest Signed-off-by: Mario Dominguez * Refs #10173: Use absolute paths when loading XML files Signed-off-by: Mario Dominguez * Refs #10173: Fix windows.h INTERFACE name collision Signed-off-by: Mario Dominguez * Refs #10173: Avoid MINMAX windows warning as error in unittests Signed-off-by: Mario Dominguez * Refs #10173: Use DEFAULT_FASTDDS_PROFILES for windows Signed-off-by: Mario Dominguez * Refs #10173: Enable internal debug in test Signed-off-by: Mario Dominguez * Refs #10173: Force log info in the test Signed-off-by: Mario Dominguez * Refs #10173: Correct windows FASTDDS_DEFAULT PROFILES env and include fastdds/log instead of fastrtps Signed-off-by: Mario Dominguez --------- Signed-off-by: Mario Dominguez (cherry picked from commit 0919ff294457546c72d5f8810eb61ec48b67e95e) # Conflicts: # include/fastrtps/xmlparser/XMLParserCommon.h # src/cpp/rtps/xmlparser/XMLParser.cpp # src/cpp/rtps/xmlparser/XMLParserCommon.cpp # src/cpp/rtps/xmlparser/XMLProfileManager.cpp * Refs #10173: Fix conflicts Signed-off-by: JesusPoderoso * Refs #10173: Fix mayor version conflicts Signed-off-by: JesusPoderoso * Fix conflicts Signed-off-by: Mario Dominguez * Fix conflicts Signed-off-by: Mario Dominguez * Avoid minmax warning in windows Signed-off-by: Mario Dominguez --------- Signed-off-by: JesusPoderoso Signed-off-by: Mario Dominguez Co-authored-by: Mario Domínguez López <116071334+Mario-DL@users.noreply.github.com> Co-authored-by: JesusPoderoso Co-authored-by: Mario Dominguez --- include/fastrtps/xmlparser/XMLParser.h | 12 ++ include/fastrtps/xmlparser/XMLParserCommon.h | 2 +- .../fastrtps/xmlparser/XMLProfileManager.h | 12 ++ src/cpp/rtps/xmlparser/XMLParser.cpp | 44 +++++- src/cpp/rtps/xmlparser/XMLParserCommon.cpp | 2 +- src/cpp/rtps/xmlparser/XMLProfileManager.cpp | 62 +++++++- test/unittest/dds/status/CMakeLists.txt | 1 + test/unittest/dynamic_types/CMakeLists.txt | 1 + test/unittest/logging/mock/MockConsumer.h | 24 +++- test/unittest/xmlparser/CMakeLists.txt | 111 ++++++++++++++ test/unittest/xmlparser/XMLLoadFileTests.cpp | 135 ++++++++++++++++++ 11 files changed, 392 insertions(+), 14 deletions(-) create mode 100644 test/unittest/xmlparser/XMLLoadFileTests.cpp diff --git a/include/fastrtps/xmlparser/XMLParser.h b/include/fastrtps/xmlparser/XMLParser.h index 500abba299e..16b2f45decf 100644 --- a/include/fastrtps/xmlparser/XMLParser.h +++ b/include/fastrtps/xmlparser/XMLParser.h @@ -120,6 +120,18 @@ class XMLParser const std::string& filename, up_base_node_t& root); + /** + * Load a XML file. + * @param filename Name for the file to be loaded. + * @param root Root node. + * @param is_default Is the default XML file. + * @return XMLP_ret::XML_OK on success, XMLP_ret::XML_ERROR in other case. + */ + static XMLP_ret loadXML( + const std::string& filename, + up_base_node_t& root, + bool is_default); + /** * Load a XML data from buffer. * @param data XML data to load. diff --git a/include/fastrtps/xmlparser/XMLParserCommon.h b/include/fastrtps/xmlparser/XMLParserCommon.h index 2ea21c53fcf..b34efa5eaa0 100644 --- a/include/fastrtps/xmlparser/XMLParserCommon.h +++ b/include/fastrtps/xmlparser/XMLParserCommon.h @@ -61,7 +61,7 @@ extern const char* SEND_BUFFER_SIZE; extern const char* TTL; extern const char* NON_BLOCKING_SEND; extern const char* WHITE_LIST; -extern const char* INTERFACE; +extern const char* NETWORK_INTERFACE; extern const char* MAX_MESSAGE_SIZE; extern const char* MAX_INITIAL_PEERS_RANGE; extern const char* KEEP_ALIVE_FREQUENCY; diff --git a/include/fastrtps/xmlparser/XMLProfileManager.h b/include/fastrtps/xmlparser/XMLProfileManager.h index 90097180fc2..def183f96c5 100644 --- a/include/fastrtps/xmlparser/XMLProfileManager.h +++ b/include/fastrtps/xmlparser/XMLProfileManager.h @@ -72,6 +72,18 @@ class XMLProfileManager RTPS_DllAPI static XMLP_ret loadXMLFile( const std::string& filename); + /** + * Load a profiles XML file. + * @param filename Name for the file to be loaded. + * @param is_default Flag to indicate if the file is a default profiles file. + * @return XMLP_ret::XML_OK if all profiles are correct, XMLP_ret::XML_NOK if some are and some are not, + * XMLP_ret::XML_ERROR in other case. + */ + + static XMLP_ret loadXMLFile( + const std::string& filename, + bool is_default); + /** * Load a profiles XML string. * @param data Buffer containing the data. diff --git a/src/cpp/rtps/xmlparser/XMLParser.cpp b/src/cpp/rtps/xmlparser/XMLParser.cpp index c787a88675e..3aab6a2e7c2 100644 --- a/src/cpp/rtps/xmlparser/XMLParser.cpp +++ b/src/cpp/rtps/xmlparser/XMLParser.cpp @@ -18,6 +18,11 @@ #include #include #include +#ifdef _WIN32 +#include +#else +#include +#endif // _WIN32 #include @@ -45,7 +50,32 @@ using namespace eprosima::fastdds::xml::detail; XMLP_ret XMLParser::loadDefaultXMLFile( up_base_node_t& root) { - return loadXML(DEFAULT_FASTRTPS_PROFILES, root); + // Use absolute path to ensure that the file is loaded only once +#ifdef _WIN32 + char current_directory[MAX_PATH]; + if (GetCurrentDirectory(MAX_PATH, current_directory) == 0) + { + EPROSIMA_LOG_ERROR(XMLPARSER, "GetCurrentDirectory failed " << GetLastError()); + } + else + { + strcat_s(current_directory, MAX_PATH, DEFAULT_FASTRTPS_PROFILES); + return loadXML(current_directory, root, true); + } +#else + char current_directory[PATH_MAX]; + if (getcwd(current_directory, PATH_MAX) == NULL) + { + EPROSIMA_LOG_ERROR(XMLPARSER, "getcwd failed " << std::strerror(errno)); + } + else + { + strcat(current_directory, "/"); + strcat(current_directory, DEFAULT_FASTRTPS_PROFILES); + return loadXML(current_directory, root, true); + } +#endif // _WIN32 + return XMLP_ret::XML_ERROR; } XMLP_ret XMLParser::parseXML( @@ -598,7 +628,7 @@ XMLP_ret XMLParser::parseXMLSocketTransportData( p_aux1 != nullptr; p_aux1 = p_aux1->NextSiblingElement()) { address = p_aux1->Name(); - if (strcmp(address, ADDRESS) == 0 || strcmp(address, INTERFACE) == 0) + if (strcmp(address, ADDRESS) == 0 || strcmp(address, NETWORK_INTERFACE) == 0) { std::string text = get_element_text(p_aux1); if (!text.empty()) @@ -1839,6 +1869,14 @@ XMLP_ret XMLParser::parseXMLConsumer( XMLP_ret XMLParser::loadXML( const std::string& filename, up_base_node_t& root) +{ + return loadXML(filename, root, false); +} + +XMLP_ret XMLParser::loadXML( + const std::string& filename, + up_base_node_t& root, + bool is_default) { if (filename.empty()) { @@ -1849,7 +1887,7 @@ XMLP_ret XMLParser::loadXML( tinyxml2::XMLDocument xmlDoc; if (tinyxml2::XMLError::XML_SUCCESS != xmlDoc.LoadFile(filename.c_str())) { - if (filename != std::string(DEFAULT_FASTRTPS_PROFILES)) + if (!is_default) { EPROSIMA_LOG_ERROR(XMLPARSER, "Error opening '" << filename << "'"); } diff --git a/src/cpp/rtps/xmlparser/XMLParserCommon.cpp b/src/cpp/rtps/xmlparser/XMLParserCommon.cpp index 4743f10abf1..03508488d45 100644 --- a/src/cpp/rtps/xmlparser/XMLParserCommon.cpp +++ b/src/cpp/rtps/xmlparser/XMLParserCommon.cpp @@ -48,7 +48,7 @@ const char* SEND_BUFFER_SIZE = "sendBufferSize"; const char* TTL = "TTL"; const char* NON_BLOCKING_SEND = "non_blocking_send"; const char* WHITE_LIST = "interfaceWhiteList"; -const char* INTERFACE = "interface"; +const char* NETWORK_INTERFACE = "interface"; const char* MAX_MESSAGE_SIZE = "maxMessageSize"; const char* MAX_INITIAL_PEERS_RANGE = "maxInitialPeersRange"; const char* KEEP_ALIVE_FREQUENCY = "keep_alive_frequency_ms"; diff --git a/src/cpp/rtps/xmlparser/XMLProfileManager.cpp b/src/cpp/rtps/xmlparser/XMLProfileManager.cpp index 5d2870f78f9..c13e70eb711 100644 --- a/src/cpp/rtps/xmlparser/XMLProfileManager.cpp +++ b/src/cpp/rtps/xmlparser/XMLProfileManager.cpp @@ -17,7 +17,9 @@ #include #ifdef _WIN32 #include -#endif // ifdef _WIN32 +#else +#include +#endif // _WIN32 #include @@ -196,10 +198,21 @@ void XMLProfileManager::loadDefaultXMLFile() // Try to load the default XML file set with an environment variable. #ifdef _WIN32 char file_path[MAX_PATH]; + char absolute_path[MAX_PATH]; + char current_directory[MAX_PATH]; + char** filename = {nullptr}; size_t size = MAX_PATH; if (getenv_s(&size, file_path, size, DEFAULT_FASTRTPS_ENV_VARIABLE) == 0 && size > 0) { - loadXMLFile(file_path); + // Use absolute path to ensure the file is loaded only once + if (GetFullPathName(file_path, MAX_PATH, absolute_path, filename) == 0) + { + EPROSIMA_LOG_ERROR(XMLPARSER, "GetFullPathName failed " << GetLastError()); + } + else + { + loadXMLFile(absolute_path); + } } // Should take into account '\0' @@ -209,13 +222,32 @@ void XMLProfileManager::loadDefaultXMLFile() // Try to load the default XML file if variable does not exist or is not set to '1' if (!(getenv_s(&size, skip_xml, size, SKIP_DEFAULT_XML_FILE) == 0 && skip_xml[0] == '1')) { - loadXMLFile(DEFAULT_FASTRTPS_PROFILES); + // Try to load the default XML file. + if (GetCurrentDirectory(MAX_PATH, current_directory) == 0) + { + EPROSIMA_LOG_ERROR(XMLPARSER, "GetCurrentDirectory failed " << GetLastError()); + } + else + { + strcat_s(current_directory, MAX_PATH, "\\"); + strcat_s(current_directory, MAX_PATH, DEFAULT_FASTRTPS_PROFILES); + loadXMLFile(current_directory, true); + } } #else + char absolute_path[PATH_MAX]; if (const char* file_path = std::getenv(DEFAULT_FASTRTPS_ENV_VARIABLE)) { - loadXMLFile(file_path); + char* res = realpath(file_path, absolute_path); + if (res) + { + loadXMLFile(absolute_path); + } + else + { + EPROSIMA_LOG_ERROR(XMLPARSER, "realpath failed " << std::strerror(errno)); + } } const char* skip_xml = std::getenv(SKIP_DEFAULT_XML_FILE); @@ -223,7 +255,16 @@ void XMLProfileManager::loadDefaultXMLFile() // Try to load the default XML file if variable does not exist or is not set to '1' if (!(skip_xml != nullptr && skip_xml[0] == '1')) { - loadXMLFile(DEFAULT_FASTRTPS_PROFILES); + if (getcwd(absolute_path, PATH_MAX) == NULL) + { + EPROSIMA_LOG_ERROR(XMLPARSER, "getcwd failed " << std::strerror(errno)); + } + else + { + strcat(absolute_path, "/"); + strcat(absolute_path, DEFAULT_FASTRTPS_PROFILES); + loadXMLFile(absolute_path, true); + } } #endif // ifdef _WIN32 @@ -309,6 +350,13 @@ XMLP_ret XMLProfileManager::loadXMLNode( XMLP_ret XMLProfileManager::loadXMLFile( const std::string& filename) +{ + return loadXMLFile(filename, false); +} + +XMLP_ret XMLProfileManager::loadXMLFile( + const std::string& filename, + bool is_default) { if (filename.empty()) { @@ -324,10 +372,10 @@ XMLP_ret XMLProfileManager::loadXMLFile( } up_base_node_t root_node; - XMLP_ret loaded_ret = XMLParser::loadXML(filename, root_node); + XMLP_ret loaded_ret = XMLParser::loadXML(filename, root_node, is_default); if (!root_node || loaded_ret != XMLP_ret::XML_OK) { - if (filename != std::string(DEFAULT_FASTRTPS_PROFILES)) + if (!is_default) { EPROSIMA_LOG_ERROR(XMLPARSER, "Error parsing '" << filename << "'"); } diff --git a/test/unittest/dds/status/CMakeLists.txt b/test/unittest/dds/status/CMakeLists.txt index bba6bb8d8c2..d6845007063 100644 --- a/test/unittest/dds/status/CMakeLists.txt +++ b/test/unittest/dds/status/CMakeLists.txt @@ -159,6 +159,7 @@ target_compile_definitions(ListenerTests PRIVATE $<$>,$>:__DEBUG> $<$:__INTERNALDEBUG> # Internal debug activated. $<$:_ENABLE_ATOMIC_ALIGNMENT_FIX> + $<$:NOMINMAX> # avoid conflic with std::min & std::max in visual studio ) target_include_directories(ListenerTests PRIVATE ${Asio_INCLUDE_DIR} diff --git a/test/unittest/dynamic_types/CMakeLists.txt b/test/unittest/dynamic_types/CMakeLists.txt index 405e5d8f44e..08e11381303 100644 --- a/test/unittest/dynamic_types/CMakeLists.txt +++ b/test/unittest/dynamic_types/CMakeLists.txt @@ -115,6 +115,7 @@ add_executable(DynamicTypesTests ${DYNAMIC_TYPES_TEST_SOURCE}) target_compile_definitions(DynamicTypesTests PRIVATE BOOST_ASIO_STANDALONE ASIO_STANDALONE + $<$:NOMINMAX> # avoid conflict with std::min & std::max in visual studio $<$>,$>:__DEBUG> $<$:__INTERNALDEBUG> # Internal debug activated. ) diff --git a/test/unittest/logging/mock/MockConsumer.h b/test/unittest/logging/mock/MockConsumer.h index 0337ad23c5d..d39f5038145 100644 --- a/test/unittest/logging/mock/MockConsumer.h +++ b/test/unittest/logging/mock/MockConsumer.h @@ -60,10 +60,20 @@ class MockConsumer : public StdoutConsumer template void wait( - Pred pred) + Pred pred, + std::chrono::seconds timeout = std::chrono::seconds::zero()) { std::unique_lock lock(mMutex); - cv_.wait(lock, pred); + + if (timeout == std::chrono::seconds::zero()) + { + cv_.wait(lock, pred); + } + else + { + cv_.wait_for(lock, timeout, pred); + } + } void wait_for_at_least_entries( @@ -75,6 +85,16 @@ class MockConsumer : public StdoutConsumer }); } + void wait_for_at_least_entries_for( + size_t num_entries, + std::chrono::seconds timeout) + { + return wait([this, num_entries]() -> bool + { + return mEntriesConsumed.size() >= num_entries; + }, timeout); + } + void clear_entries() { std::unique_lock guard(mMutex); diff --git a/test/unittest/xmlparser/CMakeLists.txt b/test/unittest/xmlparser/CMakeLists.txt index 71340f67106..2d194f6671b 100644 --- a/test/unittest/xmlparser/CMakeLists.txt +++ b/test/unittest/xmlparser/CMakeLists.txt @@ -146,6 +146,7 @@ target_compile_definitions(XMLProfileParserTests PRIVATE ASIO_STANDALONE $<$>,$>:__DEBUG> $<$:__INTERNALDEBUG> # Internal debug activated. + $<$:NOMINMAX> # avoid conflic with std::min & std::max in visual studio ) target_include_directories(XMLProfileParserTests PRIVATE ${PROJECT_SOURCE_DIR}/test/mock/rtps/Log @@ -249,6 +250,7 @@ target_compile_definitions(XMLParserTests PRIVATE ASIO_STANDALONE $<$>,$>:__DEBUG> $<$:__INTERNALDEBUG> # Internal debug activated. + $<$:NOMINMAX> # avoid conflic with std::min & std::max in visual studio ) target_include_directories(XMLParserTests PRIVATE ${PROJECT_SOURCE_DIR}/test/mock/rtps/SharedMemTransportDescriptor @@ -408,3 +410,112 @@ if(QNX) target_link_libraries(XMLEndpointParserTests socket) endif() gtest_discover_tests(XMLEndpointParserTests) + +###################################### XMLLoadFileTests ###################################################### +set(XMLLOADFILE_SOURCE + XMLLoadFileTests.cpp + ${PROJECT_SOURCE_DIR}/src/cpp/dynamic-types/AnnotationDescriptor.cpp + ${PROJECT_SOURCE_DIR}/src/cpp/dynamic-types/AnnotationParameterValue.cpp + ${PROJECT_SOURCE_DIR}/src/cpp/dynamic-types/BuiltinAnnotationsTypeObject.cpp + ${PROJECT_SOURCE_DIR}/src/cpp/dynamic-types/DynamicData.cpp + ${PROJECT_SOURCE_DIR}/src/cpp/dynamic-types/DynamicDataFactory.cpp + ${PROJECT_SOURCE_DIR}/src/cpp/dynamic-types/DynamicDataPtr.cpp + ${PROJECT_SOURCE_DIR}/src/cpp/dynamic-types/DynamicPubSubType.cpp + ${PROJECT_SOURCE_DIR}/src/cpp/dynamic-types/DynamicType.cpp + ${PROJECT_SOURCE_DIR}/src/cpp/dynamic-types/DynamicTypeBuilder.cpp + ${PROJECT_SOURCE_DIR}/src/cpp/dynamic-types/DynamicTypeBuilderFactory.cpp + ${PROJECT_SOURCE_DIR}/src/cpp/dynamic-types/DynamicTypeBuilderPtr.cpp + ${PROJECT_SOURCE_DIR}/src/cpp/dynamic-types/DynamicTypeMember.cpp + ${PROJECT_SOURCE_DIR}/src/cpp/dynamic-types/DynamicTypePtr.cpp + ${PROJECT_SOURCE_DIR}/src/cpp/dynamic-types/MemberDescriptor.cpp + ${PROJECT_SOURCE_DIR}/src/cpp/dynamic-types/TypeDescriptor.cpp + ${PROJECT_SOURCE_DIR}/src/cpp/dynamic-types/TypeIdentifier.cpp + ${PROJECT_SOURCE_DIR}/src/cpp/dynamic-types/TypeIdentifierTypes.cpp + ${PROJECT_SOURCE_DIR}/src/cpp/dynamic-types/TypeNamesGenerator.cpp + ${PROJECT_SOURCE_DIR}/src/cpp/dynamic-types/TypeObject.cpp + ${PROJECT_SOURCE_DIR}/src/cpp/dynamic-types/TypeObjectFactory.cpp + ${PROJECT_SOURCE_DIR}/src/cpp/dynamic-types/TypeObjectHashId.cpp + ${PROJECT_SOURCE_DIR}/src/cpp/dynamic-types/TypesBase.cpp + ${PROJECT_SOURCE_DIR}/src/cpp/fastdds/log/FileConsumer.cpp + ${PROJECT_SOURCE_DIR}/src/cpp/fastdds/log/Log.cpp + ${PROJECT_SOURCE_DIR}/src/cpp/fastdds/log/OStreamConsumer.cpp + ${PROJECT_SOURCE_DIR}/src/cpp/fastdds/log/StdoutConsumer.cpp + ${PROJECT_SOURCE_DIR}/src/cpp/fastdds/log/StdoutErrConsumer.cpp + ${PROJECT_SOURCE_DIR}/src/cpp/fastdds/publisher/qos/WriterQos.cpp + ${PROJECT_SOURCE_DIR}/src/cpp/fastdds/subscriber/qos/ReaderQos.cpp + ${PROJECT_SOURCE_DIR}/src/cpp/fastdds/topic/TopicDataType.cpp + ${PROJECT_SOURCE_DIR}/src/cpp/rtps/attributes/ThreadSettings.cpp + ${PROJECT_SOURCE_DIR}/src/cpp/rtps/common/Time_t.cpp + ${PROJECT_SOURCE_DIR}/src/cpp/rtps/flowcontrol/FlowControllerConsts.cpp + ${PROJECT_SOURCE_DIR}/src/cpp/rtps/flowcontrol/ThroughputControllerDescriptor.cpp + ${PROJECT_SOURCE_DIR}/src/cpp/rtps/transport/PortBasedTransportDescriptor.cpp + ${PROJECT_SOURCE_DIR}/src/cpp/rtps/xmlparser/XMLDynamicParser.cpp + ${PROJECT_SOURCE_DIR}/src/cpp/rtps/xmlparser/XMLElementParser.cpp + ${PROJECT_SOURCE_DIR}/src/cpp/rtps/xmlparser/XMLParser.cpp + ${PROJECT_SOURCE_DIR}/src/cpp/rtps/xmlparser/XMLParserCommon.cpp + ${PROJECT_SOURCE_DIR}/src/cpp/rtps/xmlparser/XMLProfileManager.cpp + ${PROJECT_SOURCE_DIR}/src/cpp/utils/IPFinder.cpp + ${PROJECT_SOURCE_DIR}/src/cpp/utils/IPLocator.cpp + ${PROJECT_SOURCE_DIR}/src/cpp/utils/md5.cpp + ${PROJECT_SOURCE_DIR}/src/cpp/utils/string_convert.cpp + ${PROJECT_SOURCE_DIR}/src/cpp/utils/SystemInfo.cpp + + # locators + ${PROJECT_SOURCE_DIR}/src/cpp/utils/IPFinder.cpp + ${PROJECT_SOURCE_DIR}/src/cpp/utils/IPLocator.cpp + ${PROJECT_SOURCE_DIR}/src/cpp/utils/SystemInfo.cpp + ) + +# External sources +if(TINYXML2_SOURCE_DIR) + list(APPEND XMLLOADFILE_SOURCE + ${TINYXML2_SOURCE_DIR}/tinyxml2.cpp + ) +endif() + +if(ANDROID) + if (ANDROID_NATIVE_API_LEVEL LESS 24) + list(APPEND XMLLOADFILE_SOURCE + ${ANDROID_IFADDRS_SOURCE_DIR}/ifaddrs.c + ) + endif() +endif() + +add_executable(XMLLoadFileTests ${XMLLOADFILE_SOURCE}) +target_compile_definitions(XMLLoadFileTests PRIVATE + BOOST_ASIO_STANDALONE + ASIO_STANDALONE + $<$:NOMINMAX> # avoid conflict with std::min & std::max in visual studio + $<$>,$>:__DEBUG> + $<$:__INTERNALDEBUG> # Internal debug activated. + HAVE_LOG_NO_INFO=0 FASTDDS_ENFORCE_LOG_INFO # Need LOG_INFO in this test + ) +target_include_directories(XMLLoadFileTests PRIVATE + ${PROJECT_SOURCE_DIR}/test/mock/dds/TypeObjectRegistry + ${PROJECT_SOURCE_DIR}/test/mock/dds/TypeObjectUtils + ${PROJECT_SOURCE_DIR}/test/mock/rtps/RTPSDomainImpl # Dependency of fastdds::xtypes::type_representation + ${PROJECT_SOURCE_DIR}/test/mock/rtps/SharedMemTransportDescriptor + ${PROJECT_SOURCE_DIR}/test/mock/rtps/TCPTransportDescriptor + ${PROJECT_SOURCE_DIR}/test/mock/rtps/TCPv4TransportDescriptor + ${PROJECT_SOURCE_DIR}/test/mock/rtps/TCPv6TransportDescriptor + ${PROJECT_SOURCE_DIR}/test/mock/rtps/UDPTransportDescriptor + ${PROJECT_SOURCE_DIR}/test/mock/rtps/UDPv4TransportDescriptor + ${PROJECT_SOURCE_DIR}/test/mock/rtps/UDPv6TransportDescriptor + ${PROJECT_SOURCE_DIR}/test/mock/rtps/RTPSParticipantAttributes + ${PROJECT_SOURCE_DIR}/include + ${PROJECT_BINARY_DIR}/include + ${PROJECT_SOURCE_DIR}/src/cpp + ${Asio_INCLUDE_DIR} + $<$:${ANDROID_IFADDRS_INCLUDE_DIR}> + ) + +target_link_libraries(XMLLoadFileTests GTest::gtest + $<$:iphlpapi$Shlwapi> + $<$:ws2_32> + ${TINYXML2_LIBRARY} + fastcdr + ) +if(QNX) + target_link_libraries(XMLLoadFileTests socket) +endif() +gtest_discover_tests(XMLLoadFileTests) diff --git a/test/unittest/xmlparser/XMLLoadFileTests.cpp b/test/unittest/xmlparser/XMLLoadFileTests.cpp new file mode 100644 index 00000000000..4d5fb1404cb --- /dev/null +++ b/test/unittest/xmlparser/XMLLoadFileTests.cpp @@ -0,0 +1,135 @@ +// Copyright 2024 Proyectos y Sistemas de Mantenimiento SL (eProsima +// +// Licensed under the Apache License, Version 2.0 (the "License"); +// you may not use this file except in compliance with the License. +// You may obtain a copy of the License at +// +// http://www.apache.org/licenses/LICENSE-2.0 +// +// Unless required by applicable law or agreed to in writing, software +// distributed under the License is distributed on an "AS IS" BASIS, +// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +// See the License for the specific language governing permissions and +// limitations under the License. + +#include +#include +#ifdef _WIN32 +#include +#else +#include +#include +#endif // ifdef _WIN32 + +#include +#include +#include +#include +#include "../logging/mock/MockConsumer.h" + +using namespace eprosima::fastdds::dds; +using namespace eprosima::fastrtps; +using namespace ::testing; + +class XMLLoadFileTests : public ::testing::Test +{ +public: + + void helper_block_for_at_least_entries_for( + uint32_t amount, + std::chrono::seconds timeout) + { + mock_consumer_->wait_for_at_least_entries_for( + amount, + timeout); + } + +protected: + + void SetUp() override + { + mock_consumer_ = new eprosima::fastdds::dds::MockConsumer(); + log_consumer_.reset(mock_consumer_); + } + + void TearDown() override + { + //! mock_consumer_ is going to be cleared in log_consumer_ destructor + } + + eprosima::fastdds::dds::MockConsumer* mock_consumer_; + std::unique_ptr log_consumer_; + +private: + + std::mutex xml_mutex_; +}; + +/* + * This test checks that the default XML file is loaded only once when there is a DEFAULT_FASTRTPS_PROFILES.xml file + * in the current directory and the environment variable FASTRTPS_DEFAULT_PROFILES_FILE is set pointing to the same + * file. + * 1. Initialize Mock Consumer to consume the LogInfo entry that the library generates when the file has been already + * parsed. Set filters to consume only the desired entry. + * 2. Get current path to set the environment variable to the DEFAULT_FASTRTPS_PROFILES.xml file. + * 3. Write the DEFAULT_FASTRTPS_PROFILES.xml file in the current directory. + * 4. Load the default XML file. + * 5. Wait for the log entry to be consumed. + */ +TEST_F(XMLLoadFileTests, load_twice_default_xml) +{ + // Register Mock Consumer + Log::ClearConsumers(); + Log::RegisterConsumer(std::move(log_consumer_)); + Log::SetVerbosity(Log::Info); + Log::SetCategoryFilter(std::regex("(XMLPARSER)")); + Log::SetErrorStringFilter(std::regex("(already parsed)")); + + // Current directory +#ifdef _WIN32 + char current_directory[MAX_PATH]; + uint32_t ret = GetCurrentDirectory(MAX_PATH, current_directory); + ASSERT_NE(ret, 0u); + strcat_s(current_directory, MAX_PATH, "\\"); + strcat_s(current_directory, MAX_PATH, xmlparser::DEFAULT_FASTRTPS_PROFILES); + // Set environment variable + _putenv_s("FASTRTPS_DEFAULT_PROFILES_FILE", current_directory); +#else + char current_directory[PATH_MAX]; + ASSERT_NE(getcwd(current_directory, PATH_MAX), (void*)NULL); + strcat(current_directory, "/"); + strcat(current_directory, xmlparser::DEFAULT_FASTRTPS_PROFILES); + // Set environment variable + setenv("FASTRTPS_DEFAULT_PROFILES_FILE", current_directory, 1); +#endif // _WIN32 + + // Write DEFAULT_FASTRTPS_PROFILES.xml + std::ofstream xmlFile; + xmlFile.open("DEFAULT_FASTRTPS_PROFILES.xml"); + xmlFile << ""; + xmlFile << ""; + xmlFile << "truetest_name"; + xmlFile << ""; + xmlFile.close(); + + // Load default XML file + xmlparser::XMLProfileManager::loadDefaultXMLFile(); + + // Log consumer + helper_block_for_at_least_entries_for(1, std::chrono::seconds(2)); + auto consumed_entries = mock_consumer_->ConsumedEntries(); + EXPECT_EQ(consumed_entries.size(), 1u); + + Log::Reset(); + Log::KillThread(); + + std::remove("DEFAULT_FASTRTPS_PROFILES.xml"); +} + +int main( + int argc, + char** argv) +{ + testing::InitGoogleTest(&argc, argv); + return RUN_ALL_TESTS(); +}