From bc2fdd5159fe375fa13fd46987ee8864d6f2f334 Mon Sep 17 00:00:00 2001 From: Justus Braun Date: Sat, 27 Jul 2024 12:53:26 +0200 Subject: [PATCH] Added tests for action name remapping. Signed-off-by: Justus Braun --- rcl_action/CMakeLists.txt | 14 ++ rcl_action/test/rcl_action/arg_macros.hpp | 81 ++++++++ .../rcl_action/test_action_name_remapping.cpp | 175 ++++++++++++++++++ 3 files changed, 270 insertions(+) create mode 100644 rcl_action/test/rcl_action/arg_macros.hpp create mode 100644 rcl_action/test/rcl_action/test_action_name_remapping.cpp diff --git a/rcl_action/CMakeLists.txt b/rcl_action/CMakeLists.txt index c4686c2ce..ad383dc69 100644 --- a/rcl_action/CMakeLists.txt +++ b/rcl_action/CMakeLists.txt @@ -219,6 +219,20 @@ if(BUILD_TESTING) src ) endif() + ament_add_gtest(test_action_name_remapping + test/rcl_action/test_action_name_remapping.cpp + ) + if(TARGET test_action_name_remapping) + target_link_libraries(test_action_name_remapping + ${PROJECT_NAME} + osrf_testing_tools_cpp::memory_tools + rcl::rcl + ${test_msgs_TARGETS} + ) + target_include_directories(test_action_name_remapping PRIVATE + src + ) + endif() endif() # Export old-style CMake variables diff --git a/rcl_action/test/rcl_action/arg_macros.hpp b/rcl_action/test/rcl_action/arg_macros.hpp new file mode 100644 index 000000000..ce574721d --- /dev/null +++ b/rcl_action/test/rcl_action/arg_macros.hpp @@ -0,0 +1,81 @@ +// Copyright 2018 Open Source Robotics Foundation, Inc. +// +// 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 RCL_ACTION__ARG_MACROS_HPP_ +#define RCL_ACTION__ARG_MACROS_HPP_ + +#include "osrf_testing_tools_cpp/scope_exit.hpp" + +#include "rcl/error_handling.h" +#include "rcl/rcl.h" +#include "rcutils/strdup.h" + +/// Helper to get around non-const args passed to rcl_init(). +char ** +copy_args(int argc, const char ** args) +{ + rcl_allocator_t allocator = rcl_get_default_allocator(); + char ** copy = static_cast(allocator.allocate(sizeof(char *) * argc, allocator.state)); + for (int i = 0; i < argc; ++i) { + copy[i] = rcutils_strdup(args[i], allocator); + } + return copy; +} + +/// Destroy args allocated by copy_args. +void +destroy_args(int argc, char ** args) +{ + rcl_allocator_t allocator = rcl_get_default_allocator(); + for (int i = 0; i < argc; ++i) { + allocator.deallocate(args[i], allocator.state); + } + allocator.deallocate(args, allocator.state); +} + +#define SCOPE_GLOBAL_ARGS(argc, argv, ...) \ + rcl_init_options_t init_options = rcl_get_zero_initialized_init_options(); \ + ASSERT_EQ(RCL_RET_OK, rcl_init_options_init(&init_options, rcl_get_default_allocator())) \ + << rcl_get_error_string().str; \ + rcl_context_t context = rcl_get_zero_initialized_context(); \ + { \ + const char * const_argv[] = {__VA_ARGS__}; \ + argc = (sizeof(const_argv) / sizeof(const char *)); \ + argv = copy_args(argc, const_argv); \ + rcl_ret_t ret = rcl_init(argc, argv, &init_options, &context); \ + ASSERT_EQ(RCL_RET_OK, ret) << rcl_get_error_string().str; \ + } \ + OSRF_TESTING_TOOLS_CPP_SCOPE_EXIT( \ + { \ + EXPECT_EQ(RCL_RET_OK, rcl_init_options_fini(&init_options)) << rcl_get_error_string().str; \ + destroy_args(argc, argv); \ + ASSERT_EQ(RCL_RET_OK, rcl_shutdown(&context)) << rcl_get_error_string().str; \ + ASSERT_EQ(RCL_RET_OK, rcl_context_fini(&context)) << rcl_get_error_string().str; \ + }) + +#define SCOPE_ARGS(local_arguments, ...) \ + { \ + local_arguments = rcl_get_zero_initialized_arguments(); \ + const char * local_argv[] = {__VA_ARGS__}; \ + unsigned int local_argc = (sizeof(local_argv) / sizeof(const char *)); \ + rcl_ret_t ret = rcl_parse_arguments( \ + local_argc, local_argv, rcl_get_default_allocator(), &local_arguments); \ + ASSERT_EQ(RCL_RET_OK, ret) << rcl_get_error_string().str; \ + } \ + OSRF_TESTING_TOOLS_CPP_SCOPE_EXIT( \ + { \ + ASSERT_EQ(RCL_RET_OK, rcl_arguments_fini(&local_arguments)); \ + }) + +#endif // RCL_ACTION__ARG_MACROS_HPP_ diff --git a/rcl_action/test/rcl_action/test_action_name_remapping.cpp b/rcl_action/test/rcl_action/test_action_name_remapping.cpp new file mode 100644 index 000000000..2bdf718a1 --- /dev/null +++ b/rcl_action/test/rcl_action/test_action_name_remapping.cpp @@ -0,0 +1,175 @@ +// Copyright 2024 Open Source Robotics Foundation, Inc. +// +// 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 +#include +#include "test_msgs/action/fibonacci.h" +#include "arg_macros.hpp" + +class TestActionNameRemappingFixture : public ::testing::Test +{ +protected: + void SetUp() override + { + } + + void TearDown() override + { + } +}; + +TEST_F(TestActionNameRemappingFixture, test_action_client_name_remapping) { + // Check that remapping works with global args passed to rcl_init + int argc; + char ** argv; + + SCOPE_GLOBAL_ARGS( + argc, argv, + "process_name", + "--ros-args", + "-r", "__node:=new_name", + "-r", "__ns:=/new_ns", + "-r", "/foo/bar:=/bar/foo"); + + rcl_node_t node = rcl_get_zero_initialized_node(); + rcl_node_options_t default_options = rcl_node_get_default_options(); + ASSERT_EQ( + RCL_RET_OK, + rcl_node_init(&node, "original_name", "/original_ns", &context, &default_options)); + + // Absolute names should be unchanged + { + const rcl_action_client_options_t action_client_options = + rcl_action_client_get_default_options(); + const rosidl_action_type_support_t * action_typesupport = + ROSIDL_GET_ACTION_TYPE_SUPPORT(test_msgs, Fibonacci); + rcl_action_client_t client = rcl_action_get_zero_initialized_client(); + rcl_ret_t ret = rcl_action_client_init( + &client, &node, action_typesupport, "/absolute_name", &action_client_options); + ASSERT_EQ(ret, RCL_RET_OK) << rcl_get_error_string().str; + EXPECT_STREQ("/absolute_name", + rcl_action_client_get_action_name(&client)) << rcl_get_error_string().str; + EXPECT_EQ(RCL_RET_OK, rcl_action_client_fini(&client, &node)) << rcl_get_error_string().str; + } + + // Namespace relative names should work + { + const rcl_action_client_options_t action_client_options = + rcl_action_client_get_default_options(); + const rosidl_action_type_support_t * action_typesupport = + ROSIDL_GET_ACTION_TYPE_SUPPORT(test_msgs, Fibonacci); + rcl_action_client_t client = rcl_action_get_zero_initialized_client(); + rcl_ret_t ret = rcl_action_client_init( + &client, &node, action_typesupport, "ns_relative_name", &action_client_options); + ASSERT_EQ(ret, RCL_RET_OK) << rcl_get_error_string().str; + EXPECT_STREQ("/new_ns/ns_relative_name", + rcl_action_client_get_action_name(&client)) << rcl_get_error_string().str; + EXPECT_EQ(RCL_RET_OK, rcl_action_client_fini(&client, &node)) << rcl_get_error_string().str; + } + + // Node relative names should work + { + const rcl_action_client_options_t action_client_options = + rcl_action_client_get_default_options(); + const rosidl_action_type_support_t * action_typesupport = + ROSIDL_GET_ACTION_TYPE_SUPPORT(test_msgs, Fibonacci); + rcl_action_client_t client = rcl_action_get_zero_initialized_client(); + rcl_ret_t ret = rcl_action_client_init( + &client, &node, action_typesupport, "~/node_relative_name", &action_client_options); + ASSERT_EQ(ret, RCL_RET_OK) << rcl_get_error_string().str; + EXPECT_STREQ("/new_ns/new_name/node_relative_name", + rcl_action_client_get_action_name(&client)) << rcl_get_error_string().str; + EXPECT_EQ(RCL_RET_OK, rcl_action_client_fini(&client, &node)) << rcl_get_error_string().str; + } + + EXPECT_EQ(RCL_RET_OK, rcl_node_fini(&node)) << rcl_get_error_string().str; +} + +TEST_F(TestActionNameRemappingFixture, test_action_server_name_remapping) { + // Check that remapping works with global args passed to rcl_init + int argc; + char ** argv; + + SCOPE_GLOBAL_ARGS( + argc, argv, + "process_name", + "--ros-args", + "-r", "__node:=new_name", + "-r", "__ns:=/new_ns", + "-r", "/foo/bar:=/bar/foo"); + + rcl_node_t node = rcl_get_zero_initialized_node(); + rcl_node_options_t default_options = rcl_node_get_default_options(); + rcl_allocator_t allocator = rcl_get_default_allocator(); + rcl_clock_t clock; + rcl_ret_t ret = rcl_clock_init(RCL_STEADY_TIME, &clock, &allocator); + ASSERT_EQ(RCL_RET_OK, ret) << rcl_get_error_string().str; + ASSERT_EQ( + RCL_RET_OK, + rcl_node_init(&node, "original_name", "/original_ns", &context, &default_options) + ); + + // Absolute names should be unchanged + { + const rcl_action_server_options_t action_server_options = + rcl_action_server_get_default_options(); + const rosidl_action_type_support_t * action_typesupport = + ROSIDL_GET_ACTION_TYPE_SUPPORT(test_msgs, Fibonacci); + rcl_action_server_t server = rcl_action_get_zero_initialized_server(); + ret = rcl_action_server_init( + &server, &node, &clock, action_typesupport, "/absolute_name", &action_server_options); + ASSERT_EQ(ret, RCL_RET_OK) << rcl_get_error_string().str; + EXPECT_STREQ( + "/absolute_name", + rcl_action_server_get_action_name(&server) + ) << rcl_get_error_string().str; + EXPECT_EQ(RCL_RET_OK, rcl_action_server_fini(&server, &node)) << rcl_get_error_string().str; + } + + // Namespace relative names should work + { + const rcl_action_server_options_t action_server_options = + rcl_action_server_get_default_options(); + const rosidl_action_type_support_t * action_typesupport = + ROSIDL_GET_ACTION_TYPE_SUPPORT(test_msgs, Fibonacci); + rcl_action_server_t server = rcl_action_get_zero_initialized_server(); + ret = rcl_action_server_init( + &server, &node, &clock, action_typesupport, "ns_relative_name", &action_server_options); + ASSERT_EQ(ret, RCL_RET_OK) << rcl_get_error_string().str; + EXPECT_STREQ( + "/new_ns/ns_relative_name", + rcl_action_server_get_action_name(&server) + ) << rcl_get_error_string().str; + EXPECT_EQ(RCL_RET_OK, rcl_action_server_fini(&server, &node)) << rcl_get_error_string().str; + } + + // Node relative names should work + { + const rcl_action_server_options_t action_server_options = + rcl_action_server_get_default_options(); + const rosidl_action_type_support_t * action_typesupport = + ROSIDL_GET_ACTION_TYPE_SUPPORT(test_msgs, Fibonacci); + rcl_action_server_t server = rcl_action_get_zero_initialized_server(); + ret = rcl_action_server_init( + &server, &node, &clock, action_typesupport, "~/node_relative_name", &action_server_options); + ASSERT_EQ(ret, RCL_RET_OK) << rcl_get_error_string().str; + EXPECT_STREQ( + "/new_ns/new_name/node_relative_name", + rcl_action_server_get_action_name(&server) + ) << rcl_get_error_string().str; + EXPECT_EQ(RCL_RET_OK, rcl_action_server_fini(&server, &node)) << rcl_get_error_string().str; + EXPECT_EQ(RCL_RET_OK, rcl_node_fini(&node)) << rcl_get_error_string().str; + } +}