From e7ecbabf57c64ebaadbf06cd7a42158cdd1c3cb0 Mon Sep 17 00:00:00 2001 From: Michael Carroll Date: Thu, 3 Aug 2023 18:11:15 +0000 Subject: [PATCH] Use subprocess rather than custom code Signed-off-by: Michael Carroll --- log/test/CMakeLists.txt | 4 - log/test/integration/CMakeLists.txt | 46 +---- log/test/integration/ChirpParams.cc | 57 ++++++ log/test/integration/ChirpParams.hh | 184 ++++-------------- log/test/integration/playback.cc | 30 +-- log/test/integration/recorder.cc | 14 +- log/test/integration/topicChirp_aux.cc | 7 +- log/test/test_config.hh.in | 24 --- src/cmd/CMakeLists.txt | 6 +- src/cmd/gz_TEST.cc | 77 ++------ test/integration/CMakeLists.txt | 29 ++- test/integration/authPubSub.cc | 17 +- test/integration/scopedTopic.cc | 14 +- test/integration/twoProcsPubSub.cc | 110 ++--------- test/integration/twoProcsSrvCall.cc | 62 +----- test/integration/twoProcsSrvCallStress.cc | 15 +- test/integration/twoProcsSrvCallSync1.cc | 14 +- .../twoProcsSrvCallWithoutInput.cc | 49 +---- .../twoProcsSrvCallWithoutInputStress.cc | 16 +- .../twoProcsSrvCallWithoutInputSync1.cc | 16 +- .../twoProcsSrvCallWithoutOutput.cc | 35 +--- .../twoProcsSrvCallWithoutOutputStress.cc | 16 +- test/test_config.hh.in | 153 --------------- 23 files changed, 258 insertions(+), 737 deletions(-) create mode 100644 log/test/integration/ChirpParams.cc delete mode 100644 log/test/test_config.hh.in diff --git a/log/test/CMakeLists.txt b/log/test/CMakeLists.txt index c11c67f90..26e40e61e 100644 --- a/log/test/CMakeLists.txt +++ b/log/test/CMakeLists.txt @@ -1,5 +1 @@ -configure_file (test_config.hh.in - ${PROJECT_BINARY_DIR}/include/log/test_config.hh -) - add_subdirectory(integration) diff --git a/log/test/integration/CMakeLists.txt b/log/test/integration/CMakeLists.txt index 3459c8aa9..5537f4511 100644 --- a/log/test/integration/CMakeLists.txt +++ b/log/test/integration/CMakeLists.txt @@ -1,5 +1,14 @@ # Integration tests + +add_library(ChirpParams STATIC ./ChirpParams.cc) +target_link_libraries(ChirpParams PUBLIC ${PROJECT_LIBRARY_TARGET_NAME}-log ${EXTRA_TEST_LIB_DEPS}) +target_compile_definitions(ChirpParams + PRIVATE TOPIC_CHIRP_EXE="$") + +gz_add_executable(topicChirp_aux topicChirp_aux.cc) +target_link_libraries(topicChirp_aux ChirpParams) + gz_build_tests( TYPE "INTEGRATION" TEST_LIST logging_tests @@ -8,6 +17,7 @@ gz_build_tests( playback.cc query.cc LIB_DEPS + ChirpParams ${PROJECT_LIBRARY_TARGET_NAME}-log ${EXTRA_TEST_LIB_DEPS} INCLUDE_DIRS @@ -21,48 +31,12 @@ if (UNIX AND NOT APPLE) endif() foreach(test_target ${logging_tests}) - set_tests_properties(${test_target} PROPERTIES ENVIRONMENT GZ_TRANSPORT_LOG_SQL_PATH=${PROJECT_SOURCE_DIR}/log/sql) target_compile_definitions(${test_target} PRIVATE GZ_TRANSPORT_LOG_SQL_PATH="${PROJECT_SOURCE_DIR}/log/sql") - target_compile_definitions(${test_target} - PRIVATE GZ_TRANSPORT_LOG_BUILD_PATH="$") - endforeach() -set (aux - topicChirp_aux.cc -) - -foreach(source_file ${aux}) - string(REGEX REPLACE ".cc" "" AUX_EXECUTABLE ${source_file}) - set(BINARY_NAME ${TEST_TYPE}_${AUX_EXECUTABLE}) - - gz_add_executable(${BINARY_NAME} ${AUX_EXECUTABLE}.cc) - - # Include the interface directories that we always need. - gz_target_interface_include_directories(${BINARY_NAME} - ${PROJECT_LIBRARY_TARGET_NAME}) - - # Link the libraries that we always need. - target_link_libraries(${BINARY_NAME} - PRIVATE - ${PROJECT_LIBRARY_TARGET_NAME} - ${log_lib_target} - gtest - ${EXTRA_TEST_LIB_DEPS} - ) - - if(UNIX) - # pthread is only available on Unix machines - target_link_libraries(${BINARY_NAME} - PRIVATE pthread) - endif() - - target_compile_definitions(${BINARY_NAME} - PRIVATE GZ_TRANSPORT_LOG_BUILD_PATH="$") -endforeach() # gz log CLI test if (HAVE_GZ_TOOLS) diff --git a/log/test/integration/ChirpParams.cc b/log/test/integration/ChirpParams.cc new file mode 100644 index 000000000..1f606f1d6 --- /dev/null +++ b/log/test/integration/ChirpParams.cc @@ -0,0 +1,57 @@ +/* + * Copyright (C) 2018 Open Source Robotics Foundation + * + * 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 "ChirpParams.hh" + + +static constexpr const char* kTopicChirpExe = TOPIC_CHIRP_EXE; + +namespace gz::transport::log::test +{ + ////////////////////////////////////////////////// + /// \brief Similar to testing::forkAndRun(), except this function + /// specifically calls the INTEGRATION_topicChirp_aux process and passes + /// it arguments to determine how it should chirp out messages over its + /// topics. + /// \param _topics A list of topic names to chirp on + /// \param _chirps The number of messages to chirp out. Each message + /// will count up starting from the value 1 and ending with the value + /// _chirps. + /// \return A handle to the process. This can be used with + /// testing::waitAndCleanupFork(). + gz::utils::Subprocess BeginChirps( + const std::vector &_topics, + const int _chirps, + const std::string &_partitionName) + { + // Argument list: + // [0]: Executable name + // [1]: Partition name + // [2]: Number of chirps + // [3]-[N]: Each topic name + // [N+1]: Null terminator, required by execv + const std::size_t numArgs = 3 + _topics.size() + 1; + + std::vector strArgs; + strArgs.reserve(numArgs-1); + strArgs.push_back(kTopicChirpExe); + strArgs.push_back(_partitionName); + strArgs.push_back(std::to_string(_chirps)); + strArgs.insert(strArgs.end(), _topics.begin(), _topics.end()); + return gz::utils::Subprocess(strArgs); + } +} // namespace gz::transport::log::test diff --git a/log/test/integration/ChirpParams.hh b/log/test/integration/ChirpParams.hh index 5a4ddaec4..e194cac84 100644 --- a/log/test/integration/ChirpParams.hh +++ b/log/test/integration/ChirpParams.hh @@ -18,162 +18,44 @@ #ifndef GZ_TRANSPORT_LOG_TEST_INTEGRATION_CHIRPPARAMS_HH_ #define GZ_TRANSPORT_LOG_TEST_INTEGRATION_CHIRPPARAMS_HH_ -#ifdef _MSC_VER -#pragma warning(push) -#pragma warning(disable: 4251) -#endif -#include -#ifdef _MSC_VER -#pragma warning(pop) -#endif -#include - #include #include +#include #include +#include - -namespace gz +namespace gz::transport::log::test { - namespace transport - { - namespace log - { - namespace test - { - /// \brief Parameter used to determine how long the topicChirp_aux - /// program will wait between emitting message chirps from its topic. - /// Value is in milliseconds. - const int DelayBetweenChirps_ms = 1; - - /// \brief Parameter used to determine how long the topicChirp_aux - /// program will wait (after it advertises) before it begins publishing - /// its message chirps. Value is in milliseconds. - const int DelayBeforePublishing_ms = 1000; - - /// \brief This is the message type that will be used by the chirping - /// topics. - using ChirpMsgType = gz::msgs::Int32; - - - ////////////////////////////////////////////////// - /// \brief Similar to testing::forkAndRun(), except this function - /// specifically calls the INTEGRATION_topicChirp_aux process and passes - /// it arguments to determine how it should chirp out messages over its - /// topics. - /// \param _topics A list of topic names to chirp on - /// \param _chirps The number of messages to chirp out. Each message - /// will count up starting from the value 1 and ending with the value - /// _chirps. - /// \return A handle to the process. This can be used with - /// testing::waitAndCleanupFork(). - testing::forkHandlerType BeginChirps( - const std::vector &_topics, - const int _chirps, - const std::string &_partitionName) - { - // Set the chirping process name - const std::string process = - GZ_TRANSPORT_LOG_BUILD_PATH"/INTEGRATION_topicChirp_aux"; - - // Argument list: - // [0]: Executable name - // [1]: Partition name - // [2]: Number of chirps - // [3]-[N]: Each topic name - // [N+1]: Null terminator, required by execv - const std::size_t numArgs = 3 + _topics.size() + 1; - - std::vector strArgs; - strArgs.reserve(numArgs-1); - strArgs.push_back(process); - strArgs.push_back(_partitionName); - strArgs.push_back(std::to_string(_chirps)); - strArgs.insert(strArgs.end(), _topics.begin(), _topics.end()); - - #ifdef _MSC_VER - std::string fullArgs; - for (std::size_t i = 0; i < strArgs.size(); ++i) - { - if (i == 0) - { - // Windows prefers quotes around the process name - fullArgs += "\""; - } - else - { - fullArgs += " "; - } - - fullArgs += strArgs[i]; - - if (i == 0) - { - fullArgs += "\""; - } - } - - char * args = new char[fullArgs.size()+1]; - std::snprintf(args, fullArgs.size()+1, "%s", fullArgs.c_str()); - - STARTUPINFO info = {sizeof(info)}; - PROCESS_INFORMATION processInfo; - - if (!CreateProcess(nullptr, args, nullptr, nullptr, - TRUE, 0, nullptr, nullptr, &info, &processInfo)) - { - std::cerr << "Error running the chirp process [" - << args << "]\n"; - } - - delete[] args; - - return processInfo; - #else - // Create a raw char* array to pass to execv - char * * args = new char*[numArgs]; - - // Allocate a char array for each argument and copy the data to it - for (std::size_t i = 0; i < strArgs.size(); ++i) - { - const std::string &arg = strArgs[i]; - args[i] = new char[arg.size()+1]; - std::snprintf(args[i], arg.size()+1, "%s", arg.c_str()); - } - - // The last item in the char array must be a nullptr, according to the - // documentation of execv - args[numArgs-1] = nullptr; - - testing::forkHandlerType pid = fork(); - - if (pid == 0) - { - if (execv(process.c_str(), args) == -1) - { - int err = errno; - std::cerr << "Error running the chirp process [" << err << "]: " - << strerror(err) << "\n"; - } - } - - // Clean up the array of arguments - for (std::size_t i = 0; i < numArgs; ++i) - { - char *arg = args[i]; - delete[] arg; - arg = nullptr; - } - delete[] args; - args = nullptr; - - return pid; - #endif - } - } - } - } -} + /// \brief Parameter used to determine how long the topicChirp_aux + /// program will wait between emitting message chirps from its topic. + /// Value is in milliseconds. + const int DelayBetweenChirps_ms = 1; + + /// \brief Parameter used to determine how long the topicChirp_aux + /// program will wait (after it advertises) before it begins publishing + /// its message chirps. Value is in milliseconds. + const int DelayBeforePublishing_ms = 1000; + + /// \brief This is the message type that will be used by the chirping + /// topics. + using ChirpMsgType = gz::msgs::Int32; + + ////////////////////////////////////////////////// + /// \brief Similar to testing::forkAndRun(), except this function + /// specifically calls the INTEGRATION_topicChirp_aux process and passes + /// it arguments to determine how it should chirp out messages over its + /// topics. + /// \param _topics A list of topic names to chirp on + /// \param _chirps The number of messages to chirp out. Each message + /// will count up starting from the value 1 and ending with the value + /// _chirps. + /// \return A handle to the process. This can be used with + /// testing::waitAndCleanupFork(). + gz::utils::Subprocess BeginChirps( + const std::vector &_topics, + const int _chirps, + const std::string &_partitionName); +} // namespace gz::transport::log::test #endif diff --git a/log/test/integration/playback.cc b/log/test/integration/playback.cc index 7ad283fa5..cc88920f8 100644 --- a/log/test/integration/playback.cc +++ b/log/test/integration/playback.cc @@ -22,8 +22,10 @@ #include #include #include +#include #include "ChirpParams.hh" +#include "test_config.hh" static std::string partition; @@ -123,11 +125,11 @@ TEST(playback, GZ_UTILS_TEST_DISABLED_ON_MAC(ReplayLog)) recorder.Start(logName)); const int numChirps = 100; - testing::forkHandlerType chirper = + auto chirper = gz::transport::log::test::BeginChirps(topics, numChirps, partition); // Wait for the chirping to finish - testing::waitAndCleanupFork(chirper); + chirper.Join(); // Wait to make sure our callbacks are done processing the incoming messages std::this_thread::sleep_for(std::chrono::seconds(1)); @@ -224,11 +226,11 @@ TEST(playback, GZ_UTILS_TEST_DISABLED_ON_MAC(ReplayLogRegex)) recorder.Start(logName)); const int numChirps = 100; - testing::forkHandlerType chirper = + auto chirper = gz::transport::log::test::BeginChirps(topics, numChirps, partition); // Wait for the chirping to finish - testing::waitAndCleanupFork(chirper); + chirper.Join(); // Wait to make sure our callbacks are done processing the incoming messages std::this_thread::sleep_for(std::chrono::seconds(1)); @@ -291,11 +293,11 @@ TEST(playback, GZ_UTILS_TEST_DISABLED_ON_MAC(RemoveTopic)) recorder.Start(logName)); const int numChirps = 100; - testing::forkHandlerType chirper = + auto chirper = gz::transport::log::test::BeginChirps(topics, numChirps, partition); // Wait for the chirping to finish - testing::waitAndCleanupFork(chirper); + chirper.Join(); // Wait to make sure our callbacks are done processing the incoming messages std::this_thread::sleep_for(std::chrono::seconds(1)); @@ -402,11 +404,11 @@ TEST(playback, GZ_UTILS_TEST_DISABLED_ON_MAC(ReplayLogMoveInstances)) recorder.Start(logName)); const int numChirps = 100; - testing::forkHandlerType chirper = + auto chirper = gz::transport::log::test::BeginChirps(topics, numChirps, partition); // Wait for the chirping to finish - testing::waitAndCleanupFork(chirper); + chirper.Join(); // Wait to make sure our callbacks are done processing the incoming messages std::this_thread::sleep_for(std::chrono::seconds(1)); @@ -469,11 +471,11 @@ TEST(playback, GZ_UTILS_TEST_DISABLED_ON_MAC(ReplayPauseResume)) recorder.Start(logName)); const int numChirps = 100; - testing::forkHandlerType chirper = + auto chirper = gz::transport::log::test::BeginChirps(topics, numChirps, partition); // Wait for the chirping to finish - testing::waitAndCleanupFork(chirper); + chirper.Join(); // Wait to make sure our callbacks are done processing the incoming messages std::this_thread::sleep_for(std::chrono::seconds(1)); @@ -591,11 +593,11 @@ TEST(playback, GZ_UTILS_TEST_DISABLED_ON_MAC(ReplayStep)) recorder.Start(logName)); const int numChirps = 100; - testing::forkHandlerType chirper = + auto chirper = gz::transport::log::test::BeginChirps(topics, numChirps, partition); // Wait for the chirping to finish - testing::waitAndCleanupFork(chirper); + chirper.Join(); // Wait to make sure our callbacks are done processing the incoming messages std::this_thread::sleep_for(std::chrono::seconds(1)); @@ -707,11 +709,11 @@ TEST(playback, GZ_UTILS_TEST_DISABLED_ON_MAC(ReplaySeek)) recorder.Start(logName)); const int numChirps = 100; - testing::forkHandlerType chirper = + auto chirper = gz::transport::log::test::BeginChirps(topics, numChirps, partition); // Wait for the chirping to finish - testing::waitAndCleanupFork(chirper); + chirper.Join(); // Wait to make sure our callbacks are done processing the incoming messages std::this_thread::sleep_for(std::chrono::seconds(1)); diff --git a/log/test/integration/recorder.cc b/log/test/integration/recorder.cc index 333d111a2..e999efe79 100644 --- a/log/test/integration/recorder.cc +++ b/log/test/integration/recorder.cc @@ -26,6 +26,8 @@ #include #include +#include "test_config.hh" + #include "ChirpParams.hh" static std::string partition; @@ -94,11 +96,11 @@ TEST(recorder, EXPECT_EQ(logName, recorder.Filename()); const int numChirps = 100; - testing::forkHandlerType chirper = + auto chirper = gz::transport::log::test::BeginChirps(topics, numChirps, partition); // Wait for the chirping to finish - testing::waitAndCleanupFork(chirper); + chirper.Join(); // Wait to make sure our callbacks are done processing the incoming messages std::this_thread::sleep_for(std::chrono::seconds(1)); @@ -158,7 +160,7 @@ TEST(recorder, BeginRecordingTopicsAfterAdvertisement) const int numChirps = static_cast( std::ceil(secondsToChirpFor * 1000.0/static_cast(delay_ms))); - testing::forkHandlerType chirper = + auto chirper = gz::transport::log::test::BeginChirps(topics, numChirps, partition); const int waitBeforeSubscribing_ms = @@ -180,7 +182,7 @@ TEST(recorder, BeginRecordingTopicsAfterAdvertisement) gz::transport::log::RecorderError::SUCCESS); // Wait for the chirping to finish - testing::waitAndCleanupFork(chirper); + chirper.Join(); // Wait to make sure our callbacks are done processing the incoming messages std::this_thread::sleep_for(std::chrono::seconds(1)); @@ -231,11 +233,11 @@ void RecordPatternBeforeAdvertisement(const std::regex &_pattern) gz::transport::log::RecorderError::SUCCESS); const int numChirps = 100; - testing::forkHandlerType chirper = + auto chirper = gz::transport::log::test::BeginChirps(topics, numChirps, partition); // Wait for the chirping to finish - testing::waitAndCleanupFork(chirper); + chirper.Join(); // Wait to make sure our callbacks are done processing the incoming messages std::this_thread::sleep_for(std::chrono::seconds(1)); diff --git a/log/test/integration/topicChirp_aux.cc b/log/test/integration/topicChirp_aux.cc index ae67e26ec..a39f5bea4 100644 --- a/log/test/integration/topicChirp_aux.cc +++ b/log/test/integration/topicChirp_aux.cc @@ -15,11 +15,10 @@ * */ -#include - #include #include +#include #include #include "ChirpParams.hh" @@ -38,13 +37,11 @@ void chirp(const std::vector &_topicNames, gz::transport::Node node; - using MsgType = gz::transport::log::test::ChirpMsgType; - std::vector publishers; for (const std::string &topic : _topicNames) { - publishers.push_back(node.Advertise(topic)); + publishers.push_back(node.Advertise(topic)); } std::this_thread::sleep_for( diff --git a/log/test/test_config.hh.in b/log/test/test_config.hh.in deleted file mode 100644 index 9c354ae0b..000000000 --- a/log/test/test_config.hh.in +++ /dev/null @@ -1,24 +0,0 @@ -/* - * Copyright (C) 2019 Open Source Robotics Foundation - * - * 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. - * -*/ - -#ifndef GZ_TRANSPORT_LOG_TEST_CONFIG_HH_ -#define GZ_TRANSPORT_LOG_TEST_CONFIG_HH_ - - -#define GZ_TRANSPORT_LOG_TEST_PATH "@CMAKE_SOURCE_DIR@/log/test" - -#endif diff --git a/src/cmd/CMakeLists.txt b/src/cmd/CMakeLists.txt index 269d66f38..91aabdab5 100644 --- a/src/cmd/CMakeLists.txt +++ b/src/cmd/CMakeLists.txt @@ -46,9 +46,11 @@ foreach(test ${test_list}) # auxiliary files from. Using a generator expression here is useful for # multi-configuration generators, like Visual Studio. target_compile_definitions(${test} PRIVATE - "DETAIL_GZ_TRANSPORT_TEST_DIR=\"$\"" "GZ_TEST_LIBRARY_PATH=\"$\"" - "PROJECT_SOURCE_DIR=\"${PROJECT_SOURCE_DIR}\"") + "PROJECT_SOURCE_DIR=\"${PROJECT_SOURCE_DIR}\"" + "TWO_PROCS_PUBLISHER_EXE=\"$\"" + "GZ_EXE=\"${HAVE_GZ_TOOLS}\"" + ) endforeach() diff --git a/src/cmd/gz_TEST.cc b/src/cmd/gz_TEST.cc index 4babd53e0..753ae1db1 100644 --- a/src/cmd/gz_TEST.cc +++ b/src/cmd/gz_TEST.cc @@ -20,19 +20,17 @@ #include #include +#include #include #include + #include +#include #include "gtest/gtest.h" #include "gz/transport/Node.hh" #include "test_config.hh" -#ifdef _MSC_VER -# define popen _popen -# define pclose _pclose -#endif - using namespace gz; static std::string g_partition; // NOLINT(*) @@ -40,27 +38,8 @@ static std::string g_topicCBStr; // NOLINT(*) static const std::string g_gzVersion("--force-version " + // NOLINT(*) std::string(GZ_VERSION_FULL)); -///////////////////////////////////////////////// -std::string custom_exec_str(std::string _cmd) -{ - _cmd += " 2>&1"; - FILE *pipe = popen(_cmd.c_str(), "r"); - - if (!pipe) - return "ERROR"; - - char buffer[128]; - std::string result = ""; - - while (!feof(pipe)) - { - if (fgets(buffer, 128, pipe) != NULL) - result += buffer; - } - - pclose(pipe); - return result; -} +static constexpr const char * kGzExe = GZ_EXE; +static constexpr const char * kTwoProcsPublisherExe = TWO_PROCS_PUBLISHER_EXE; ////////////////////////////////////////////////// /// \brief Provide a service. @@ -81,33 +60,27 @@ void topicCB(const msgs::StringMsg &_msg) /// \brief Check 'gz topic -l' running the advertiser on a different process. TEST(gzTest, GZ_UTILS_TEST_DISABLED_ON_MAC(TopicList)) { - // Launch a new publisher process that advertises a topic. - std::string publisher_path = testing::portablePathUnion( - GZ_TRANSPORT_TEST_DIR, - "INTEGRATION_twoProcsPublisher_aux"); - - testing::forkHandlerType pi = testing::forkAndRun(publisher_path.c_str(), - g_partition.c_str()); - - // Check the 'gz topic -l' command. - std::string gz = std::string(GZ_PATH); + auto proc = gz::utils::Subprocess({kTwoProcsPublisherExe, g_partition}); unsigned int retries = 0u; bool topicFound = false; while (!topicFound && retries++ < 10u) { - std::string output = custom_exec_str(gz + " topic -l " + g_gzVersion); + auto gz = gz::utils::Subprocess({kGzExe, "topic", "-l", g_gzVersion}); + auto output = gz.Stdout(); + + std::cout << "Output: " << std::endl; + std::cout << output << std::endl; + topicFound = output == "/foo\n"; std::this_thread::sleep_for(std::chrono::milliseconds(300)); } EXPECT_TRUE(topicFound); - - // Wait for the child process to return. - testing::waitAndCleanupFork(pi); } +/* ////////////////////////////////////////////////// /// \brief Check 'gz topic -i' running the advertiser on a different process. TEST(gzTest, TopicInfo) @@ -527,26 +500,4 @@ TEST(gzTest, TopicHelpVsCompletionFlags) EXPECT_NE(std::string::npos, helpOutput.find(flag)) << helpOutput; } } - -///////////////////////////////////////////////// -/// Main -int main(int argc, char **argv) -{ - // Get a random partition name. - g_partition = testing::getRandomNumber(); - - // Set the partition name for this process. - setenv("GZ_PARTITION", g_partition.c_str(), 1); - - // Make sure that we load the library recently built and not the one installed - // in your system. - // Save the current value of LD_LIBRARY_PATH. - std::string value = ""; - transport::env("LD_LIBRARY_PATH", value); - // Add the directory where Gazebo Transport has been built. - value = std::string(GZ_TEST_LIBRARY_PATH) + ":" + value; - setenv("LD_LIBRARY_PATH", value.c_str(), 1); - - ::testing::InitGoogleTest(&argc, argv); - return RUN_ALL_TESTS(); -} +*/ diff --git a/test/integration/CMakeLists.txt b/test/integration/CMakeLists.txt index 858962a0e..bea650004 100644 --- a/test/integration/CMakeLists.txt +++ b/test/integration/CMakeLists.txt @@ -56,20 +56,33 @@ set(auxiliary_files # Build the auxiliary files. foreach(AUX_EXECUTABLE ${auxiliary_files}) - gz_add_executable(INTEGRATION_${AUX_EXECUTABLE} ${AUX_EXECUTABLE}.cc) + gz_add_executable(${AUX_EXECUTABLE} ${AUX_EXECUTABLE}.cc) # Link the libraries that we always need. - target_link_libraries(INTEGRATION_${AUX_EXECUTABLE} + target_link_libraries(${AUX_EXECUTABLE} PRIVATE ${PROJECT_LIBRARY_TARGET_NAME} gtest ${EXTRA_TEST_LIB_DEPS} ) +endforeach(AUX_EXECUTABLE) - if(UNIX) - # pthread is only available on Unix machines - target_link_libraries(INTEGRATION_${AUX_EXECUTABLE} - PRIVATE pthread) - endif() -endforeach(AUX_EXECUTABLE) +foreach(test ${test_list}) + target_compile_definitions(${test} PRIVATE + "AUTH_PUB_SUB_SUBSCRIBER_INVALID_EXE=\"$\"" + "FAST_PUB_EXE=\"$\"" + "PUB_EXE=\"$\"" + "PUB_THROTTLED_EXE=\"$\"" + "SCOPED_TOPIC_SUBSCRIBER_EXE=\"$\"" + + "TWO_PROCS_PUBLISHER_EXE=\"$\"" + "TWO_PROCS_PUB_SUB_SUBSCRIBER_EXE=\"$\"" + + "TWO_PROCS_SRV_CALL_REPLIER_EXE=\"$\"" + "TWO_PROCS_SRV_CALL_REPLIER_INC_EXE=\"$\"" + "TWO_PROCS_SRV_CALL_WITHOUT_INPUT_REPLIER_EXE=\"$\"" + "TWO_PROCS_SRV_CALL_WITHOUT_INPUT_REPLIER_INC_EXE=\"$\"" + "TWO_PROCS_SRV_CALL_WITHOUT_OUTPUT_REPLIER_EXE=\"$\"" + "TWO_PROCS_SRV_CALL_WITHOUT_OUTPUT_REPLIER_INC_EXE=\"$\"") +endforeach() diff --git a/test/integration/authPubSub.cc b/test/integration/authPubSub.cc index f0fd6eaf5..ef44f7fc6 100644 --- a/test/integration/authPubSub.cc +++ b/test/integration/authPubSub.cc @@ -29,6 +29,8 @@ #include "gtest/gtest.h" #include "gz/transport/Node.hh" #include "gz/transport/TransportTypes.hh" +#include + #include "test_config.hh" using namespace gz; @@ -36,6 +38,9 @@ using namespace gz; static std::string partition; // NOLINT(*) static std::string g_topic = "/foo"; // NOLINT(*) +static constexpr const char * kAuthPubSubSubscriberInvalid = + AUTH_PUB_SUB_SUBSCRIBER_INVALID_EXE; + ////////////////////////////////////////////////// TEST(authPubSub, InvalidAuth) { @@ -50,13 +55,8 @@ TEST(authPubSub, InvalidAuth) // No subscribers yet. EXPECT_FALSE(pub.HasConnections()); - std::string subscriberPath = testing::portablePathUnion( - GZ_TRANSPORT_TEST_DIR, - "INTEGRATION_authPubSubSubscriberInvalid_aux"); - - // Start the subscriber in another process with incorrect credentials. - testing::forkHandlerType pi = testing::forkAndRun(subscriberPath.c_str(), - partition.c_str(), "bad", "invalid"); + auto pi = gz::utils::Subprocess( + {kAuthPubSubSubscriberInvalid, partition, "bad", "invalid"}); msgs::Int32 msg; msg.set_data(1); @@ -74,9 +74,6 @@ TEST(authPubSub, InvalidAuth) EXPECT_TRUE(pub.Publish(msg)); std::this_thread::sleep_for(std::chrono::milliseconds(500)); } - - // The other process should exit without receiving any of the messages. - testing::waitAndCleanupFork(pi); } ////////////////////////////////////////////////// diff --git a/test/integration/scopedTopic.cc b/test/integration/scopedTopic.cc index 9c36a935f..a394fd65d 100644 --- a/test/integration/scopedTopic.cc +++ b/test/integration/scopedTopic.cc @@ -21,6 +21,8 @@ #include "gz/transport/AdvertiseOptions.hh" #include "gz/transport/Node.hh" +#include + #include "gtest/gtest.h" #include "test_config.hh" @@ -30,18 +32,16 @@ static std::string partition; // NOLINT(*) static std::string g_topic = "/foo"; // NOLINT(*) static int data = 5; +static constexpr const char* kScopedTopicSubscriberExe = + SCOPED_TOPIC_SUBSCRIBER_EXE; + ////////////////////////////////////////////////// /// \brief Two different nodes, each one running in a different process. The /// publisher advertises the topic as "process". This test checks that the topic /// is not seen by the other node running in a different process. TEST(ScopedTopicTest, ProcessTest) { - std::string subscriber_path = testing::portablePathUnion( - GZ_TRANSPORT_TEST_DIR, - "INTEGRATION_scopedTopicSubscriber_aux"); - - testing::forkHandlerType pi = testing::forkAndRun(subscriber_path.c_str(), - partition.c_str()); + auto pi = gz::utils::Subprocess({kScopedTopicSubscriberExe, partition}); msgs::Int32 msg; msg.set_data(data); @@ -56,8 +56,6 @@ TEST(ScopedTopicTest, ProcessTest) EXPECT_TRUE(pub.Publish(msg)); std::this_thread::sleep_for(std::chrono::milliseconds(500)); EXPECT_TRUE(pub.Publish(msg)); - - testing::waitAndCleanupFork(pi); } ////////////////////////////////////////////////// diff --git a/test/integration/twoProcsPubSub.cc b/test/integration/twoProcsPubSub.cc index a5a82f20f..903a2e206 100644 --- a/test/integration/twoProcsPubSub.cc +++ b/test/integration/twoProcsPubSub.cc @@ -18,6 +18,7 @@ #include #include +#include #include #include "gtest/gtest.h" @@ -38,6 +39,12 @@ static bool cbVectorExecuted = false; static bool cbRawExecuted = false; static int counter = 0; +static constexpr const char* kFastPubExe = FAST_PUB_EXE; +static constexpr const char* kPubExe = PUB_EXE; +static constexpr const char* kPubThrottledExe = PUB_THROTTLED_EXE; +static constexpr const char* kTwoProcsPublisherExe = TWO_PROCS_PUBLISHER_EXE; +static constexpr const char* kTwoProcsPubSubSubscriberExe = TWO_PROCS_PUB_SUB_SUBSCRIBER_EXE; + ////////////////////////////////////////////////// /// \brief Initialize some global variables. void reset() @@ -109,12 +116,7 @@ TEST(twoProcPubSub, PubSubTwoProcsThreeNodes) // No subscribers yet. EXPECT_FALSE(pub.HasConnections()); - std::string subscriberPath = testing::portablePathUnion( - GZ_TRANSPORT_TEST_DIR, - "INTEGRATION_twoProcsPubSubSubscriber_aux"); - - testing::forkHandlerType pi = testing::forkAndRun(subscriberPath.c_str(), - partition.c_str()); + auto pi = gz::utils::Subprocess({kTwoProcsPubSubSubscriberExe, partition}); msgs::Vector3d msg; msg.set_x(1.0); @@ -132,8 +134,6 @@ TEST(twoProcPubSub, PubSubTwoProcsThreeNodes) EXPECT_TRUE(pub.Publish(msg)); std::this_thread::sleep_for(std::chrono::milliseconds(500)); } - - testing::waitAndCleanupFork(pi); } ////////////////////////////////////////////////// @@ -148,12 +148,7 @@ TEST(twoProcPubSub, RawPubSubTwoProcsThreeNodes) // No subscribers yet. EXPECT_FALSE(pub.HasConnections()); - std::string subscriberPath = testing::portablePathUnion( - GZ_TRANSPORT_TEST_DIR, - "INTEGRATION_twoProcsPubSubSubscriber_aux"); - - testing::forkHandlerType pi = testing::forkAndRun(subscriberPath.c_str(), - partition.c_str()); + auto pi = gz::utils::Subprocess({kTwoProcsPubSubSubscriberExe, partition}); msgs::Vector3d msg; msg.set_x(1.0); @@ -174,8 +169,6 @@ TEST(twoProcPubSub, RawPubSubTwoProcsThreeNodes) EXPECT_TRUE(pub.PublishRaw(msg.SerializeAsString(), msg.GetTypeName())); std::this_thread::sleep_for(std::chrono::milliseconds(500)); } - - testing::waitAndCleanupFork(pi); } ////////////////////////////////////////////////// @@ -183,12 +176,7 @@ TEST(twoProcPubSub, RawPubSubTwoProcsThreeNodes) /// the advertised types. TEST(twoProcPubSub, PubSubWrongTypesOnSubscription) { - std::string publisherPath = testing::portablePathUnion( - GZ_TRANSPORT_TEST_DIR, - "INTEGRATION_twoProcsPublisher_aux"); - - testing::forkHandlerType pi = testing::forkAndRun(publisherPath.c_str(), - partition.c_str()); + auto pi = gz::utils::Subprocess({kTwoProcsPublisherExe, partition}); reset(); @@ -202,20 +190,13 @@ TEST(twoProcPubSub, PubSubWrongTypesOnSubscription) EXPECT_FALSE(cbExecuted); reset(); - - testing::waitAndCleanupFork(pi); } ////////////////////////////////////////////////// /// \brief Same as above, but using a raw subscription. TEST(twoProcPubSub, PubRawSubWrongTypesOnSubscription) { - std::string publisherPath = testing::portablePathUnion( - GZ_TRANSPORT_TEST_DIR, - "INTEGRATION_twoProcsPublisher_aux"); - - testing::forkHandlerType pi = testing::forkAndRun(publisherPath.c_str(), - partition.c_str()); + auto pi = gz::utils::Subprocess({kTwoProcsPublisherExe, partition}); reset(); @@ -230,8 +211,6 @@ TEST(twoProcPubSub, PubRawSubWrongTypesOnSubscription) EXPECT_FALSE(cbRawExecuted); reset(); - - testing::waitAndCleanupFork(pi); } ////////////////////////////////////////////////// @@ -242,12 +221,7 @@ TEST(twoProcPubSub, PubRawSubWrongTypesOnSubscription) /// (correct and generic). TEST(twoProcPubSub, PubSubWrongTypesTwoSubscribers) { - std::string publisherPath = testing::portablePathUnion( - GZ_TRANSPORT_TEST_DIR, - "INTEGRATION_twoProcsPublisher_aux"); - - testing::forkHandlerType pi = testing::forkAndRun(publisherPath.c_str(), - partition.c_str()); + auto pi = gz::utils::Subprocess({kTwoProcsPublisherExe, partition}); reset(); @@ -263,15 +237,12 @@ TEST(twoProcPubSub, PubSubWrongTypesTwoSubscribers) // Wait some time before publishing. std::this_thread::sleep_for(std::chrono::milliseconds(2500)); - // Check that the message was not received. EXPECT_FALSE(cbExecuted); EXPECT_TRUE(cbVectorExecuted); EXPECT_TRUE(genericCbExecuted); reset(); - - testing::waitAndCleanupFork(pi); } ////////////////////////////////////////////////// @@ -282,12 +253,7 @@ TEST(twoProcPubSub, PubSubWrongTypesTwoSubscribers) /// callbacks are executed (correct and generic). TEST(twoProcPubSub, PubSubWrongTypesTwoRawSubscribers) { - std::string publisherPath = testing::portablePathUnion( - GZ_TRANSPORT_TEST_DIR, - "INTEGRATION_twoProcsPublisher_aux"); - - testing::forkHandlerType pi = testing::forkAndRun(publisherPath.c_str(), - partition.c_str()); + auto pi = gz::utils::Subprocess({kTwoProcsPublisherExe, partition}); reset(); @@ -334,8 +300,6 @@ TEST(twoProcPubSub, PubSubWrongTypesTwoRawSubscribers) EXPECT_TRUE(genericRawCbExecuted); reset(); - - testing::waitAndCleanupFork(pi); } ////////////////////////////////////////////////// @@ -345,18 +309,13 @@ TEST(twoProcPubSub, PubSubWrongTypesTwoRawSubscribers) /// the prompt termination of the publisher. TEST(twoProcPubSub, FastPublisher) { - std::string publisherPath = testing::portablePathUnion( - GZ_TRANSPORT_TEST_DIR, "INTEGRATION_fastPub_aux"); - - testing::forkHandlerType pi = testing::forkAndRun(publisherPath.c_str(), - partition.c_str()); + auto pi = gz::utils::Subprocess({kFastPubExe, partition}); reset(); transport::Node node; EXPECT_TRUE(node.Subscribe(g_topic, cbVector)); - testing::waitAndCleanupFork(pi); } ////////////////////////////////////////////////// @@ -365,11 +324,7 @@ TEST(twoProcPubSub, FastPublisher) /// by the subscriber. TEST(twoProcPubSub, SubThrottled) { - std::string publisherPath = testing::portablePathUnion( - GZ_TRANSPORT_TEST_DIR, "INTEGRATION_pub_aux"); - - testing::forkHandlerType pi = testing::forkAndRun(publisherPath.c_str(), - partition.c_str()); + auto pi = gz::utils::Subprocess({kPubExe, partition}); reset(); @@ -387,8 +342,6 @@ TEST(twoProcPubSub, SubThrottled) EXPECT_LT(counter, 5); reset(); - - testing::waitAndCleanupFork(pi); } ////////////////////////////////////////////////// @@ -396,11 +349,7 @@ TEST(twoProcPubSub, SubThrottled) /// processes. The publisher publishes at a throttled frequency. TEST(twoProcPubSub, PubThrottled) { - std::string publisherPath = testing::portablePathUnion( - GZ_TRANSPORT_TEST_DIR, "INTEGRATION_pub_aux_throttled"); - - testing::forkHandlerType pi = testing::forkAndRun(publisherPath.c_str(), - partition.c_str()); + auto pi = gz::utils::Subprocess({kPubThrottledExe, partition}); reset(); @@ -416,8 +365,6 @@ TEST(twoProcPubSub, PubThrottled) EXPECT_LT(counter, 5); reset(); - - testing::waitAndCleanupFork(pi); } ////////////////////////////////////////////////// @@ -425,12 +372,7 @@ TEST(twoProcPubSub, PubThrottled) /// using a callback that accepts message information. TEST(twoProcPubSub, PubSubMessageInfo) { - std::string publisherPath = testing::portablePathUnion( - GZ_TRANSPORT_TEST_DIR, "INTEGRATION_twoProcsPublisher_aux"); - - testing::forkHandlerType pi = testing::forkAndRun(publisherPath.c_str(), - partition.c_str()); - + auto pi = gz::utils::Subprocess({kTwoProcsPublisherExe, partition}); reset(); transport::Node node; @@ -443,8 +385,6 @@ TEST(twoProcPubSub, PubSubMessageInfo) EXPECT_FALSE(cbInfoExecuted); reset(); - - testing::waitAndCleanupFork(pi); } ////////////////////////////////////////////////// @@ -453,11 +393,7 @@ TEST(twoProcPubSub, PubSubMessageInfo) /// available topics. TEST(twoProcPubSub, TopicList) { - std::string publisherPath = testing::portablePathUnion( - GZ_TRANSPORT_TEST_DIR, "INTEGRATION_twoProcsPublisher_aux"); - - testing::forkHandlerType pi = testing::forkAndRun(publisherPath.c_str(), - partition.c_str()); + auto pi = gz::utils::Subprocess({kTwoProcsPublisherExe, partition}); reset(); @@ -494,8 +430,6 @@ TEST(twoProcPubSub, TopicList) EXPECT_LT(elapsed2, 2); reset(); - - testing::waitAndCleanupFork(pi); } ////////////////////////////////////////////////// @@ -504,11 +438,7 @@ TEST(twoProcPubSub, TopicList) /// about the topic. TEST(twoProcPubSub, TopicInfo) { - std::string publisherPath = testing::portablePathUnion( - GZ_TRANSPORT_TEST_DIR, "INTEGRATION_twoProcsPublisher_aux"); - - testing::forkHandlerType pi = testing::forkAndRun(publisherPath.c_str(), - partition.c_str()); + auto pi = gz::utils::Subprocess({kTwoProcsPublisherExe, partition}); reset(); @@ -529,8 +459,6 @@ TEST(twoProcPubSub, TopicInfo) EXPECT_EQ(publishers.front().MsgTypeName(), "gz.msgs.Vector3d"); reset(); - - testing::waitAndCleanupFork(pi); } ////////////////////////////////////////////////// diff --git a/test/integration/twoProcsSrvCall.cc b/test/integration/twoProcsSrvCall.cc index 059d3ab00..26d20473f 100644 --- a/test/integration/twoProcsSrvCall.cc +++ b/test/integration/twoProcsSrvCall.cc @@ -23,6 +23,7 @@ #include "gz/transport/Node.hh" #include "gz/transport/TopicUtils.hh" +#include "gz/utils/Subprocess.hh" #include "gtest/gtest.h" #include "test_config.hh" @@ -36,6 +37,8 @@ static std::string g_topic = "/foo"; // NOLINT(*) static int data = 5; static int counter = 0; +static constexpr const char *kTwoProcsSrvCallReplierExe = TWO_PROCS_SRV_CALL_REPLIER_EXE; + ////////////////////////////////////////////////// /// \brief Initialize some global variables. void reset() @@ -68,12 +71,7 @@ void wrongResponse(const msgs::Vector3d &/*_rep*/, bool /*_result*/) /// advertises a service and the other requests a few service calls. TEST(twoProcSrvCall, SrvTwoProcs) { - std::string responser_path = testing::portablePathUnion( - GZ_TRANSPORT_TEST_DIR, - "INTEGRATION_twoProcsSrvCallReplier_aux"); - - testing::forkHandlerType pi = testing::forkAndRun(responser_path.c_str(), - partition.c_str()); + auto pi = gz::utils::Subprocess({kTwoProcsSrvCallReplierExe, partition}); reset(); @@ -111,9 +109,6 @@ TEST(twoProcSrvCall, SrvTwoProcs) EXPECT_EQ(counter, 1); reset(); - - // Wait for the child process to return. - testing::waitAndCleanupFork(pi); } ////////////////////////////////////////////////// @@ -127,12 +122,7 @@ TEST(twoProcSrvCall, SrvRequestWrongReq) bool result; unsigned int timeout = 1000; - std::string responser_path = testing::portablePathUnion( - GZ_TRANSPORT_TEST_DIR, - "INTEGRATION_twoProcsSrvCallReplier_aux"); - - testing::forkHandlerType pi = testing::forkAndRun(responser_path.c_str(), - partition.c_str()); + auto pi = gz::utils::Subprocess({kTwoProcsSrvCallReplierExe, partition}); wrongReq.set_x(1); wrongReq.set_y(2); @@ -151,9 +141,6 @@ TEST(twoProcSrvCall, SrvRequestWrongReq) EXPECT_FALSE(node.Request(g_topic, wrongReq, timeout, rep, result)); reset(); - - // Wait for the child process to return. - testing::waitAndCleanupFork(pi); } ////////////////////////////////////////////////// @@ -167,13 +154,7 @@ TEST(twoProcSrvCall, SrvRequestWrongRep) bool result; unsigned int timeout = 1000; - std::string responser_path = testing::portablePathUnion( - GZ_TRANSPORT_TEST_DIR, - "INTEGRATION_twoProcsSrvCallReplier_aux"); - - - testing::forkHandlerType pi = testing::forkAndRun(responser_path.c_str(), - partition.c_str()); + auto pi = gz::utils::Subprocess({kTwoProcsSrvCallReplierExe, partition}); req.set_data(data); @@ -190,9 +171,6 @@ TEST(twoProcSrvCall, SrvRequestWrongRep) EXPECT_FALSE(node.Request(g_topic, req, timeout, wrongRep, result)); reset(); - - // Wait for the child process to return. - testing::waitAndCleanupFork(pi); } ////////////////////////////////////////////////// @@ -208,12 +186,7 @@ TEST(twoProcSrvCall, SrvTwoRequestsOneWrong) bool result; unsigned int timeout = 2000; - std::string responser_path = testing::portablePathUnion( - GZ_TRANSPORT_TEST_DIR, - "INTEGRATION_twoProcsSrvCallReplier_aux"); - - testing::forkHandlerType pi = testing::forkAndRun(responser_path.c_str(), - partition.c_str()); + auto pi = gz::utils::Subprocess({kTwoProcsSrvCallReplierExe, partition}); req.set_data(data); @@ -238,9 +211,6 @@ TEST(twoProcSrvCall, SrvTwoRequestsOneWrong) EXPECT_TRUE(responseExecuted); reset(); - - // Wait for the child process to return. - testing::waitAndCleanupFork(pi); } ////////////////////////////////////////////////// @@ -249,12 +219,7 @@ TEST(twoProcSrvCall, SrvTwoRequestsOneWrong) /// of available services. TEST(twoProcSrvCall, ServiceList) { - std::string publisherPath = testing::portablePathUnion( - GZ_TRANSPORT_TEST_DIR, - "INTEGRATION_twoProcsSrvCallReplier_aux"); - - testing::forkHandlerType pi = testing::forkAndRun(publisherPath.c_str(), - partition.c_str()); + auto pi = gz::utils::Subprocess({kTwoProcsSrvCallReplierExe, partition}); reset(); @@ -291,8 +256,6 @@ TEST(twoProcSrvCall, ServiceList) << "] Elapsed1[" << elapsed1.count() << "]"; reset(); - - testing::waitAndCleanupFork(pi); } ////////////////////////////////////////////////// @@ -301,12 +264,7 @@ TEST(twoProcSrvCall, ServiceList) /// information about the service. TEST(twoProcSrvCall, ServiceInfo) { - std::string publisherPath = testing::portablePathUnion( - GZ_TRANSPORT_TEST_DIR, - "INTEGRATION_twoProcsSrvCallReplier_aux"); - - testing::forkHandlerType pi = testing::forkAndRun(publisherPath.c_str(), - partition.c_str()); + auto pi = gz::utils::Subprocess({kTwoProcsSrvCallReplierExe, partition}); reset(); @@ -328,8 +286,6 @@ TEST(twoProcSrvCall, ServiceInfo) EXPECT_EQ(publishers.front().RepTypeName(), "gz.msgs.Int32"); reset(); - - testing::waitAndCleanupFork(pi); } ////////////////////////////////////////////////// diff --git a/test/integration/twoProcsSrvCallStress.cc b/test/integration/twoProcsSrvCallStress.cc index 2f9d71265..27001975a 100644 --- a/test/integration/twoProcsSrvCallStress.cc +++ b/test/integration/twoProcsSrvCallStress.cc @@ -21,6 +21,9 @@ #include #include "gz/transport/Node.hh" + +#include + #include "gtest/gtest.h" #include "test_config.hh" @@ -29,15 +32,12 @@ using namespace gz; static std::string partition; // NOLINT(*) static std::string g_topic = "/foo"; // NOLINT(*) +static constexpr const char * kTwoProcsSrvReplierIncExe = TWO_PROCS_SRV_CALL_REPLIER_INC_EXE; + ////////////////////////////////////////////////// TEST(twoProcSrvCall, ThousandCalls) { - std::string responser_path = testing::portablePathUnion( - GZ_TRANSPORT_TEST_DIR, - "INTEGRATION_twoProcsSrvCallReplierInc_aux"); - - testing::forkHandlerType pi = testing::forkAndRun(responser_path.c_str(), - partition.c_str()); + auto pi = gz::utils::Subprocess({kTwoProcsSrvReplierIncExe, partition}); msgs::Int32 req; msgs::Int32 response; @@ -56,9 +56,6 @@ TEST(twoProcSrvCall, ThousandCalls) ASSERT_TRUE(result); EXPECT_EQ(i, response.data()); } - - // Need to kill the responser node running on an external process. - testing::killFork(pi); } ////////////////////////////////////////////////// diff --git a/test/integration/twoProcsSrvCallSync1.cc b/test/integration/twoProcsSrvCallSync1.cc index ef93771da..74862517a 100644 --- a/test/integration/twoProcsSrvCallSync1.cc +++ b/test/integration/twoProcsSrvCallSync1.cc @@ -21,6 +21,8 @@ #include #include "gz/transport/Node.hh" +#include + #include "gtest/gtest.h" #include "test_config.hh" @@ -30,6 +32,8 @@ static std::string partition; // NOLINT(*) static std::string g_topic = "/foo"; // NOLINT(*) static int data = 5; +static constexpr const char * kTwoProcsSrvCallReplierExe = TWO_PROCS_SRV_CALL_REPLIER_EXE; + ////////////////////////////////////////////////// /// \brief This test spawns a service responser and a service requester. The /// synchronous requester uses a wrong service's name. The test should verify @@ -37,12 +41,7 @@ static int data = 5; /// the timeout. TEST(twoProcSrvCallSync1, SrvTwoProcs) { - std::string responser_path = testing::portablePathUnion( - GZ_TRANSPORT_TEST_DIR, - "INTEGRATION_twoProcsSrvCallReplier_aux"); - - testing::forkHandlerType pi = testing::forkAndRun(responser_path.c_str(), - partition.c_str()); + auto pi = gz::utils::Subprocess({kTwoProcsSrvCallReplierExe, partition}); int64_t timeout = 500; msgs::Int32 req; @@ -71,9 +70,6 @@ TEST(twoProcSrvCallSync1, SrvTwoProcs) // Check if the elapsed time was close to the timeout. auto diff = std::max(elapsed, timeout) - std::min(elapsed, timeout); EXPECT_LT(diff, 200); - - // Wait for the child process to return. - testing::waitAndCleanupFork(pi); } ////////////////////////////////////////////////// diff --git a/test/integration/twoProcsSrvCallWithoutInput.cc b/test/integration/twoProcsSrvCallWithoutInput.cc index d98c112a0..5e47351c7 100644 --- a/test/integration/twoProcsSrvCallWithoutInput.cc +++ b/test/integration/twoProcsSrvCallWithoutInput.cc @@ -23,6 +23,9 @@ #include "gz/transport/Node.hh" #include "gz/transport/TopicUtils.hh" + +#include + #include "gtest/gtest.h" #include "test_config.hh" @@ -36,6 +39,8 @@ static std::string g_topic = "/foo"; // NOLINT(*) static int g_data = 5; static int g_counter = 0; +static constexpr const char * kTwoProcsSrvCallWithoutInputReplierExe = TWO_PROCS_SRV_CALL_WITHOUT_INPUT_REPLIER_EXE; + ////////////////////////////////////////////////// /// \brief Initialize some global variables. void reset() @@ -69,12 +74,7 @@ void wrongResponse(const msgs::Vector3d &/*_rep*/, bool /*_result*/) /// calls. TEST(twoProcSrvCallWithoutInput, SrvTwoProcs) { - std::string responser_path = testing::portablePathUnion( - GZ_TRANSPORT_TEST_DIR, - "INTEGRATION_twoProcsSrvCallWithoutInputReplier_aux"); - - testing::forkHandlerType pi = testing::forkAndRun(responser_path.c_str(), - g_partition.c_str()); + auto pi = gz::utils::Subprocess({kTwoProcsSrvCallWithoutInputReplierExe, g_partition}); reset(); @@ -109,9 +109,6 @@ TEST(twoProcSrvCallWithoutInput, SrvTwoProcs) EXPECT_EQ(g_counter, 1); reset(); - - // Wait for the child process to return. - testing::waitAndCleanupFork(pi); } ////////////////////////////////////////////////// @@ -124,12 +121,7 @@ TEST(twoProcSrvCallWithoutInput, SrvRequestWrongRep) bool result; unsigned int timeout = 1000; - std::string responser_path = testing::portablePathUnion( - GZ_TRANSPORT_TEST_DIR, - "INTEGRATION_twoProcsSrvCallWithoutInputReplier_aux"); - - testing::forkHandlerType pi = testing::forkAndRun(responser_path.c_str(), - g_partition.c_str()); + auto pi = gz::utils::Subprocess({kTwoProcsSrvCallWithoutInputReplierExe, g_partition}); reset(); @@ -144,9 +136,6 @@ TEST(twoProcSrvCallWithoutInput, SrvRequestWrongRep) EXPECT_FALSE(node.Request(g_topic, timeout, wrongRep, result)); reset(); - - // Wait for the child process to return. - testing::waitAndCleanupFork(pi); } ////////////////////////////////////////////////// @@ -161,12 +150,7 @@ TEST(twoProcSrvCallWithoutInput, SrvTwoRequestsOneWrong) bool result; unsigned int timeout = 2000; - std::string responser_path = testing::portablePathUnion( - GZ_TRANSPORT_TEST_DIR, - "INTEGRATION_twoProcsSrvCallWithoutInputReplier_aux"); - - testing::forkHandlerType pi = testing::forkAndRun(responser_path.c_str(), - g_partition.c_str()); + auto pi = gz::utils::Subprocess({kTwoProcsSrvCallWithoutInputReplierExe, g_partition}); reset(); @@ -189,9 +173,6 @@ TEST(twoProcSrvCallWithoutInput, SrvTwoRequestsOneWrong) EXPECT_TRUE(g_responseExecuted); reset(); - - // Wait for the child process to return. - testing::waitAndCleanupFork(pi); } ////////////////////////////////////////////////// @@ -204,8 +185,7 @@ TEST(twoProcSrvCallWithoutInput, ServiceList) GZ_TRANSPORT_TEST_DIR, "INTEGRATION_twoProcsSrvCallWithoutInputReplier_aux"); - testing::forkHandlerType pi = testing::forkAndRun(publisherPath.c_str(), - g_partition.c_str()); + auto pi = gz::utils::Subprocess({kTwoProcsSrvCallWithoutInputReplierExe, g_partition}); reset(); @@ -241,8 +221,6 @@ TEST(twoProcSrvCallWithoutInput, ServiceList) EXPECT_LE(elapsed2, elapsed1); reset(); - - testing::waitAndCleanupFork(pi); } ////////////////////////////////////////////////// @@ -251,12 +229,7 @@ TEST(twoProcSrvCallWithoutInput, ServiceList) /// getting information about the service. TEST(twoProcSrvCallWithoutInput, ServiceInfo) { - std::string publisherPath = testing::portablePathUnion( - GZ_TRANSPORT_TEST_DIR, - "INTEGRATION_twoProcsSrvCallWithoutInputReplier_aux"); - - testing::forkHandlerType pi = testing::forkAndRun(publisherPath.c_str(), - g_partition.c_str()); + auto pi = gz::utils::Subprocess({kTwoProcsSrvCallWithoutInputReplierExe, g_partition}); reset(); @@ -278,8 +251,6 @@ TEST(twoProcSrvCallWithoutInput, ServiceInfo) EXPECT_EQ(publishers.front().RepTypeName(), "gz.msgs.Int32"); reset(); - - testing::waitAndCleanupFork(pi); } ////////////////////////////////////////////////// diff --git a/test/integration/twoProcsSrvCallWithoutInputStress.cc b/test/integration/twoProcsSrvCallWithoutInputStress.cc index 972cce3a5..dfa8dd7a3 100644 --- a/test/integration/twoProcsSrvCallWithoutInputStress.cc +++ b/test/integration/twoProcsSrvCallWithoutInputStress.cc @@ -21,6 +21,8 @@ #include #include "gz/transport/Node.hh" +#include + #include "gtest/gtest.h" #include "test_config.hh" @@ -29,15 +31,14 @@ using namespace gz; static std::string g_partition; // NOLINT(*) static std::string g_topic = "/foo"; // NOLINT(*) +static constexpr const char * kTwoProcsSrvCallWithoutInputReplierIncExe = + TWO_PROCS_SRV_CALL_WITHOUT_INPUT_REPLIER_INC_EXE; + ////////////////////////////////////////////////// TEST(twoProcSrvCallWithoutInput, ThousandCalls) { - std::string responser_path = testing::portablePathUnion( - GZ_TRANSPORT_TEST_DIR, - "INTEGRATION_twoProcsSrvCallWithoutInputReplierInc_aux"); - - testing::forkHandlerType pi = testing::forkAndRun(responser_path.c_str(), - g_partition.c_str()); + auto pi = gz::utils::Subprocess( + {kTwoProcsSrvCallWithoutInputReplierIncExe, g_partition}); msgs::Int32 response; bool result; @@ -53,9 +54,6 @@ TEST(twoProcSrvCallWithoutInput, ThousandCalls) // Check the service response. ASSERT_TRUE(result); } - - // Need to kill the responser node running on an external process. - testing::killFork(pi); } ////////////////////////////////////////////////// diff --git a/test/integration/twoProcsSrvCallWithoutInputSync1.cc b/test/integration/twoProcsSrvCallWithoutInputSync1.cc index d2177b375..0a72f616f 100644 --- a/test/integration/twoProcsSrvCallWithoutInputSync1.cc +++ b/test/integration/twoProcsSrvCallWithoutInputSync1.cc @@ -21,6 +21,8 @@ #include #include "gz/transport/Node.hh" +#include + #include "gtest/gtest.h" #include "test_config.hh" @@ -29,6 +31,9 @@ using namespace gz; static std::string g_partition; // NOLINT(*) static std::string g_topic = "/foo"; // NOLINT(*) +static constexpr const char * kTwoProcsSrvCallWithoutInputReplierExe = + TWO_PROCS_SRV_CALL_WITHOUT_INPUT_REPLIER_EXE; + ////////////////////////////////////////////////// /// \brief This test spawns a service that doesn't accept input parameters. The /// synchronous requester uses a wrong service's name. The test should verify @@ -36,12 +41,8 @@ static std::string g_topic = "/foo"; // NOLINT(*) /// the timeout. TEST(twoProcSrvCallWithoutInputSync1, SrvTwoProcs) { - std::string responser_path = testing::portablePathUnion( - GZ_TRANSPORT_TEST_DIR, - "INTEGRATION_twoProcsSrvCallWithoutInputReplier_aux"); - - testing::forkHandlerType pi = testing::forkAndRun(responser_path.c_str(), - g_partition.c_str()); + auto pi = gz::utils::Subprocess( + {kTwoProcsSrvCallWithoutInputReplierExe, g_partition}); int64_t timeout = 500; msgs::Int32 rep; @@ -66,9 +67,6 @@ TEST(twoProcSrvCallWithoutInputSync1, SrvTwoProcs) // Check if the elapsed time was close to the timeout. auto diff = std::max(elapsed, timeout) - std::min(elapsed, timeout); EXPECT_LT(diff, 200); - - // Wait for the child process to return. - testing::waitAndCleanupFork(pi); } ////////////////////////////////////////////////// diff --git a/test/integration/twoProcsSrvCallWithoutOutput.cc b/test/integration/twoProcsSrvCallWithoutOutput.cc index 526e2283e..c76857607 100644 --- a/test/integration/twoProcsSrvCallWithoutOutput.cc +++ b/test/integration/twoProcsSrvCallWithoutOutput.cc @@ -22,6 +22,7 @@ #include "gz/transport/Node.hh" #include "gz/transport/TopicUtils.hh" +#include #include "gtest/gtest.h" #include "test_config.hh" @@ -34,6 +35,9 @@ static std::string g_partition; // NOLINT(*) static std::string g_topic = "/foo"; // NOLINT(*) static int g_counter = 0; +static constexpr const char * kTwoProcsSrvCallWithoutOutputReplierExe = + TWO_PROCS_SRV_CALL_WITHOUT_OUTPUT_REPLIER_EXE; + ////////////////////////////////////////////////// /// \brief Initialize some global variables. void reset() @@ -51,12 +55,8 @@ TEST(twoProcSrvCallWithoutOutput, SrvRequestWrongReq) { msgs::Vector3d wrongReq; - std::string responser_path = testing::portablePathUnion( - GZ_TRANSPORT_TEST_DIR, - "INTEGRATION_twoProcsSrvCallWithoutOutputReplier_aux"); - - testing::forkHandlerType pi = testing::forkAndRun(responser_path.c_str(), - g_partition.c_str()); + auto pi = gz::utils::Subprocess( + {kTwoProcsSrvCallWithoutOutputReplierExe, g_partition}); wrongReq.set_x(1); wrongReq.set_y(2); @@ -72,9 +72,6 @@ TEST(twoProcSrvCallWithoutOutput, SrvRequestWrongReq) EXPECT_FALSE(g_responseExecuted); reset(); - - // Wait for the child process to return. - testing::waitAndCleanupFork(pi); } ////////////////////////////////////////////////// @@ -83,12 +80,8 @@ TEST(twoProcSrvCallWithoutOutput, SrvRequestWrongReq) /// getting the list of available services. TEST(twoProcSrvCallWithoutOutput, ServiceList) { - std::string publisherPath = testing::portablePathUnion( - GZ_TRANSPORT_TEST_DIR, - "INTEGRATION_twoProcsSrvCallWithoutOutputReplier_aux"); - - testing::forkHandlerType pi = testing::forkAndRun(publisherPath.c_str(), - g_partition.c_str()); + auto pi = gz::utils::Subprocess( + {kTwoProcsSrvCallWithoutOutputReplierExe, g_partition}); reset(); @@ -124,8 +117,6 @@ TEST(twoProcSrvCallWithoutOutput, ServiceList) EXPECT_LE(elapsed2, elapsed1); reset(); - - testing::waitAndCleanupFork(pi); } ////////////////////////////////////////////////// @@ -134,12 +125,8 @@ TEST(twoProcSrvCallWithoutOutput, ServiceList) /// getting information about the service. TEST(twoProcSrvCallWithoutOutput, ServiceInfo) { - std::string publisherPath = testing::portablePathUnion( - GZ_TRANSPORT_TEST_DIR, - "INTEGRATION_twoProcsSrvCallWithoutOutputReplier_aux"); - - testing::forkHandlerType pi = testing::forkAndRun(publisherPath.c_str(), - g_partition.c_str()); + auto pi = gz::utils::Subprocess( + {kTwoProcsSrvCallWithoutOutputReplierExe, g_partition}); reset(); @@ -160,8 +147,6 @@ TEST(twoProcSrvCallWithoutOutput, ServiceInfo) EXPECT_EQ(publishers.front().ReqTypeName(), "gz.msgs.Int32"); reset(); - - testing::waitAndCleanupFork(pi); } ////////////////////////////////////////////////// diff --git a/test/integration/twoProcsSrvCallWithoutOutputStress.cc b/test/integration/twoProcsSrvCallWithoutOutputStress.cc index 3d76b95ec..e5df941dc 100644 --- a/test/integration/twoProcsSrvCallWithoutOutputStress.cc +++ b/test/integration/twoProcsSrvCallWithoutOutputStress.cc @@ -21,6 +21,8 @@ #include #include "gz/transport/Node.hh" +#include + #include "gtest/gtest.h" #include "test_config.hh" @@ -29,15 +31,14 @@ using namespace gz; static std::string g_partition; // NOLINT(*) static std::string g_topic = "/foo"; // NOLINT(*) +static constexpr const char* kTwoProcsSrvCallWithoutOutputReplierInc = + TWO_PROCS_SRV_CALL_WITHOUT_OUTPUT_REPLIER_INC_EXE; + ////////////////////////////////////////////////// TEST(twoProcSrvCallWithoutOuput, ThousandCalls) { - std::string responser_path = testing::portablePathUnion( - GZ_TRANSPORT_TEST_DIR, - "INTEGRATION_twoProcsSrvCallWithoutOutputReplierInc_aux"); - - testing::forkHandlerType pi = testing::forkAndRun(responser_path.c_str(), - g_partition.c_str()); + auto pi = gz::utils::Subprocess( + {kTwoProcsSrvCallWithoutOutputReplierInc, g_partition}); msgs::Int32 req; transport::Node node; @@ -49,9 +50,6 @@ TEST(twoProcSrvCallWithoutOuput, ThousandCalls) req.set_data(i); ASSERT_TRUE(node.Request(g_topic, req)); } - - // Need to kill the responser node running on an external process. - testing::killFork(pi); } ////////////////////////////////////////////////// diff --git a/test/test_config.hh.in b/test/test_config.hh.in index bc7ea350a..8276a1b1f 100644 --- a/test/test_config.hh.in +++ b/test/test_config.hh.in @@ -60,37 +60,6 @@ #include "gz/transport/Helpers.hh" -#if (_MSC_VER >= 1400) // Visual Studio 2005 - #include - - /// \brief setenv/unstenv are not present in Windows. Define them to make - /// the code portable. - /// \param[in] _name Variable name. - /// \param[in] _value Value. - /// \param[in] _rewrite If 'name' does exist in the environment, then its - /// value is changed to 'value' if 'rewrite' is nonzero. If overwrite is - /// zero, then the value of 'name' is not changed. - /// /return 0 on success or -1 on error. - int setenv(const char *_name, const char *_value, int /*_rewrite*/) - { - std::stringstream sstr; - std::string name = _name; - std::string value = _value; - sstr << name << '=' << value; - return _putenv(sstr.str().c_str()); - } - - /// \brief Deletes an environment variable. - /// \param[in] _name Variable name. - void unsetenv(const char *_name) - { - std::stringstream sstr; - std::string name = _name; - sstr << name << '='; - _putenv(sstr.str().c_str()); - } -#endif - namespace testing { /// \brief Join _str1 and _str2 considering both as storing system paths. @@ -113,128 +82,6 @@ namespace testing #endif } -#ifdef _WIN32 - using forkHandlerType = PROCESS_INFORMATION; -#else - using forkHandlerType = pid_t; -#endif - - /// \brief create a new process and run command on it. This function is - /// implementing the creation of a new process on both Linux (fork) and - /// Windows (CreateProcess) and the execution of the command provided. - /// \param[in] _command The full system path to the binary to run into the - /// new process. - /// \param[in] _partition Name of the Gazebo partition (GZ_PARTITION) - /// \param[in] _username Username for authentication - /// (GZ_TRANSPORT_USERNAME) - /// \param[in] _password Password for authentication - /// (GZ_TRANSPORT_PASSWORD) - /// \return On success, the PID of the child process is returned in the - /// parent, an 0 is returned in the child. On failure, -1 is returned in the - /// parent and no child process is created. - forkHandlerType forkAndRun(const char *_command, const char *_partition, - const char *_username = nullptr, const char *_password = nullptr) - { -#ifdef _WIN32 - STARTUPINFO info= {sizeof(info)}; - PROCESS_INFORMATION processInfo; - - char cmd[500]; - // We should put quotes around the _command string to make sure we are - // robust to file paths that contain spaces. - gz_strcpy(cmd, "\""); - gz_strcat(cmd, _command); - gz_strcat(cmd, "\""); - gz_strcat(cmd, " "); - gz_strcat(cmd, _partition); - - if (_username && _password) - { - gz_strcat(cmd, " "); - gz_strcat(cmd, _username); - gz_strcat(cmd, " "); - gz_strcat(cmd, _password); - } - - // We set the first argument to NULL, because we want the behavior that - // CreateProcess exhibits when the first argument is NULL: i.e. Windows will - // automatically add the .exe extension onto the filename. When the first - // argument is non-NULL, it will not automatically add the extension, which - // makes more work for us. - // - // It should also be noted that the lookup behavior for the application is - // different when the first argument is non-NULL, so we should take that - // into consideration when determining what to put into the first and second - // arguments of CreateProcess. - if (!CreateProcess(NULL, const_cast(cmd), NULL, NULL, - TRUE, 0, NULL, NULL, &info, &processInfo)) - { - std::cerr << "CreateProcess call failed: " << cmd << std::endl; - } - - return processInfo; -#else - pid_t pid = fork(); - - if (pid == 0) - { - if (_username && _password) - { - if (execl(_command, _command, _partition, _username, _password, - reinterpret_cast(0)) == -1) - { - std::cerr << "Error running execl call: " << _command << std::endl; - } - } - else - { - if (execl(_command, _command, _partition, - reinterpret_cast(0)) == -1) - { - std::cerr << "Error running execl call: " << _command << std::endl; - } - } - } - - return pid; -#endif - } - - /// \brief Wait for the end of a process and handle the termination - /// \param[in] pi Process handler of the process to wait for - /// (PROCESS_INFORMATION in windows or forkHandlerType in UNIX). - void waitAndCleanupFork(const forkHandlerType pi) - { -#ifdef _WIN32 - // Wait until child process exits. - WaitForSingleObject(pi.hProcess, INFINITE); - - // Close process and thread handler. - CloseHandle(pi.hProcess); - CloseHandle(pi.hThread); -#else - // Wait for the child process to return. - int status; - waitpid(pi, &status, 0); - if (status == -1) - std::cerr << "Error while running waitpid" << std::endl; -#endif - } - - /// \brief Send a termination signal to the process handled by pi. - /// \param[in] pi Process handler of the process to stop - /// (PROCESS_INFORMATION in windows or forkHandlerType in UNIX). - void killFork(const forkHandlerType pi) - { -#ifdef _WIN32 - // TerminateProcess return 0 on error - if (TerminateProcess(pi.hProcess, 0) == 0) - std::cerr << "Error running TerminateProcess: " << GetLastError(); -#else - kill(pi, SIGTERM); -#endif - } - /// \brief Get a random number based on an integer converted to string. /// \return A random integer converted to string. std::string getRandomNumber()