diff --git a/rcl/src/rcl/node.c b/rcl/src/rcl/node.c index 4afc40f53..12d24b3a4 100644 --- a/rcl/src/rcl/node.c +++ b/rcl/src/rcl/node.c @@ -54,6 +54,7 @@ extern "C" #include "./context_impl.h" const char * const RCL_DISABLE_LOANED_MESSAGES_ENV_VAR = "ROS_DISABLE_LOANED_MESSAGES"; +const char * const RCL_NAMESPACE_ENV_VAR = "ROS_NAMESPACE"; struct rcl_node_impl_s { @@ -121,6 +122,7 @@ rcl_node_init( rcl_context_t * context, const rcl_node_options_t * options) { + const rmw_guard_condition_t * rmw_graph_guard_condition = NULL; rcl_guard_condition_options_t graph_guard_condition_options = rcl_guard_condition_get_default_options(); @@ -128,6 +130,19 @@ rcl_node_init( rcl_ret_t fail_ret = RCL_RET_ERROR; char * remapped_node_name = NULL; + const char * env_error_str = NULL; + const char * env_val = NULL; + env_error_str = rcutils_get_env(RCL_NAMESPACE_ENV_VAR, &env_val); + if (NULL != env_error_str) { + RCL_SET_ERROR_MSG_WITH_FORMAT_STRING( + "Error getting env var: '" RCUTILS_STRINGIFY(RCL_NAMESPACE_ENV_VAR) "': %s\n", + env_error_str); + return RCL_RET_ERROR; + } + if (NULL != env_val && 0 != strlen(env_val)) { + namespace_ = env_val; + } + // Check options and allocator first, so allocator can be used for errors. RCL_CHECK_ARGUMENT_FOR_NULL(options, RCL_RET_INVALID_ARGUMENT); const rcl_allocator_t * allocator = &options->allocator; diff --git a/rcl/test/rcl/test_node.cpp b/rcl/test/rcl/test_node.cpp index 716fb5ff1..c7b48d185 100644 --- a/rcl/test/rcl/test_node.cpp +++ b/rcl/test/rcl/test_node.cpp @@ -1043,3 +1043,45 @@ TEST_F(CLASSNAME(TestNodeFixture, RMW_IMPLEMENTATION), test_rcl_get_disable_loan EXPECT_FALSE(disable_loaned_message); } } + +/* Tests node namespace override + */ +TEST_F(CLASSNAME(TestNodeFixture, RMW_IMPLEMENTATION), test_rcl_node_namespace_override) { + { + const char * expected_namespace = "/bar/foo"; + ASSERT_TRUE(rcutils_set_env("ROS2_NAMESPACE", expected_namespace)); + + osrf_testing_tools_cpp::memory_tools::enable_monitoring_in_all_threads(); + rcl_ret_t ret; + // Initialize rcl with rcl_init(). + rcl_init_options_t init_options = rcl_get_zero_initialized_init_options(); + ret = rcl_init_options_init(&init_options, rcl_get_default_allocator()); + 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; + }); + EXPECT_EQ(RCL_RET_OK, rcl_init_options_set_domain_id(&init_options, 42)); + const char * name = "test_rcl_node_namespace_override"; + const char * namespace_ = "/ns"; + rcl_node_options_t default_options = rcl_node_get_default_options(); + rcl_context_t context = rcl_get_zero_initialized_context(); + ret = rcl_init(0, nullptr, &init_options, &context); + ASSERT_EQ(RCL_RET_OK, ret); + // Create a normal node. + rcl_node_t node = rcl_get_zero_initialized_node(); + ret = rcl_node_init(&node, name, namespace_, &context, &default_options); + ASSERT_EQ(RCL_RET_OK, ret); + + // Check that the node namespace is overridden + ASSERT_STREQ(expected_namespace, rcl_node_get_namespace(&node)); + + OSRF_TESTING_TOOLS_CPP_SCOPE_EXIT( + { + osrf_testing_tools_cpp::memory_tools::disable_monitoring_in_all_threads(); + ASSERT_EQ(RCL_RET_OK, rcl_node_fini(&node)); + ASSERT_EQ(RCL_RET_OK, rcl_shutdown(&context)); + ASSERT_EQ(RCL_RET_OK, rcl_context_fini(&context)); + }); + } +}