diff --git a/rcl/test/rcl/test_get_type_description_service.cpp b/rcl/test/rcl/test_get_type_description_service.cpp index e2571e75c..580d6def5 100644 --- a/rcl/test/rcl/test_get_type_description_service.cpp +++ b/rcl/test/rcl/test_get_type_description_service.cpp @@ -14,7 +14,9 @@ #include +#include #include +#include #include "rcl/error_handling.h" #include "rcl/graph.h" @@ -104,6 +106,55 @@ static bool service_exists( return type_name_found; } +static bool service_not_exists( + const rcl_node_t * node_ptr, const char * service_name, + const char * service_type, std::chrono::milliseconds timeout) +{ + rcl_allocator_t allocator = rcl_get_default_allocator(); + + // Wait for a maximum of timeout milliseconds for the service to go away + // Note that this is not just the negation of service_exists; we actually + // want to wait until the service goes away + auto start_time = std::chrono::system_clock::now(); + while (std::chrono::system_clock::now() - start_time < timeout) { + rcl_names_and_types_t srv_names_and_types = rcl_get_zero_initialized_names_and_types(); + + if ( + RCL_RET_OK != rcl_get_service_names_and_types( + node_ptr, + &allocator, &srv_names_and_types)) + { + return false; + } + + OSRF_TESTING_TOOLS_CPP_SCOPE_EXIT( + { + EXPECT_EQ(RCL_RET_OK, rcl_names_and_types_fini(&srv_names_and_types)); + }); + + if (srv_names_and_types.names.size == 0) { + return true; + } + + if (!string_in_array(&(srv_names_and_types.names), service_name)) { + return true; + } + + // If we make it here, the service name was in the array. If the *type* isn't, then there is + // another service with this name, which we can ignore. + for (size_t i = 0; i < srv_names_and_types.names.size; ++i) { + if (string_in_array(&(srv_names_and_types.types[i]), service_type)) { + // Both the name and type were here, so the service currently exists. Continue waiting + break; + } + } + + std::this_thread::sleep_for(std::chrono::milliseconds(10)); + } + + return false; +} + class CLASSNAME (TestGetTypeDescSrvFixture, RMW_IMPLEMENTATION) : public ::testing::Test { public: @@ -119,27 +170,23 @@ class CLASSNAME (TestGetTypeDescSrvFixture, RMW_IMPLEMENTATION) : public ::testi void SetUp() { rcl_ret_t ret; + 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( { - 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; - }); - this->context_ptr = new rcl_context_t; - *this->context_ptr = rcl_get_zero_initialized_context(); - ret = rcl_init(0, nullptr, &init_options, this->context_ptr); - ASSERT_EQ(RCL_RET_OK, ret) << rcl_get_error_string().str; - } + EXPECT_EQ(RCL_RET_OK, rcl_init_options_fini(&init_options)) << rcl_get_error_string().str; + }); + this->context_ptr = new rcl_context_t; + *this->context_ptr = rcl_get_zero_initialized_context(); + ret = rcl_init(0, nullptr, &init_options, this->context_ptr); + ASSERT_EQ(RCL_RET_OK, ret) << rcl_get_error_string().str; this->node_ptr = new rcl_node_t; *this->node_ptr = rcl_get_zero_initialized_node(); const char * name = "test_service_node"; rcl_node_options_t node_options = rcl_node_get_default_options(); ret = rcl_node_init(this->node_ptr, name, "", this->context_ptr, &node_options); ASSERT_EQ(RCL_RET_OK, ret) << rcl_get_error_string().str; - ret = rcl_node_type_description_service_init(node_ptr); - ASSERT_EQ(RCL_RET_OK, ret) << rcl_get_error_string().str; const char * node_fqn = rcl_node_get_fully_qualified_name(this->node_ptr); snprintf( @@ -165,23 +212,27 @@ class CLASSNAME (TestGetTypeDescSrvFixture, RMW_IMPLEMENTATION) : public ::testi TEST_F( CLASSNAME(TestGetTypeDescSrvFixture, RMW_IMPLEMENTATION), test_service_init_and_fini_functions) { + // Service does not initially exist EXPECT_TRUE( - service_exists( + service_not_exists( this->node_ptr, this->get_type_description_service_name, - GET_TYPE_DESCRIPTION_SRV_TYPE_NAME)); - EXPECT_EQ(RCL_RET_OK, rcl_node_type_description_service_fini(this->node_ptr)); - EXPECT_FALSE( - service_exists( - this->node_ptr, this->get_type_description_service_name, - GET_TYPE_DESCRIPTION_SRV_TYPE_NAME)); - EXPECT_EQ(RCL_RET_NOT_INIT, rcl_node_type_description_service_fini(this->node_ptr)); + GET_TYPE_DESCRIPTION_SRV_TYPE_NAME, std::chrono::seconds(5))); + // Once the type descrition service is init, then it appear in the graph EXPECT_EQ(RCL_RET_OK, rcl_node_type_description_service_init(this->node_ptr)); EXPECT_TRUE( service_exists( this->node_ptr, this->get_type_description_service_name, GET_TYPE_DESCRIPTION_SRV_TYPE_NAME)); - EXPECT_EQ(RCL_RET_ALREADY_INIT, rcl_node_type_description_service_init(this->node_ptr)); + + // Once the type description service is fini, then it no longer appears in the graph + EXPECT_EQ(RCL_RET_OK, rcl_node_type_description_service_fini(this->node_ptr)); + EXPECT_TRUE( + service_not_exists( + this->node_ptr, this->get_type_description_service_name, + GET_TYPE_DESCRIPTION_SRV_TYPE_NAME, std::chrono::seconds(5))); + + EXPECT_EQ(RCL_RET_NOT_INIT, rcl_node_type_description_service_fini(this->node_ptr)); } /* Basic nominal test of the ~/get_type_description service. */ @@ -190,6 +241,9 @@ TEST_F(CLASSNAME(TestGetTypeDescSrvFixture, RMW_IMPLEMENTATION), test_service_no const rosidl_service_type_support_t * ts = ROSIDL_GET_SRV_TYPE_SUPPORT( type_description_interfaces, srv, GetTypeDescription); + // Create type description service. + EXPECT_EQ(RCL_RET_OK, rcl_node_type_description_service_init(this->node_ptr)); + // Create client. rcl_client_t client = rcl_get_zero_initialized_client(); rcl_client_options_t client_options = rcl_client_get_default_options(); @@ -201,6 +255,9 @@ TEST_F(CLASSNAME(TestGetTypeDescSrvFixture, RMW_IMPLEMENTATION), test_service_no { rcl_ret_t ret = rcl_client_fini(&client, this->node_ptr); EXPECT_EQ(RCL_RET_OK, ret) << rcl_get_error_string().str; + + ret = rcl_node_type_description_service_fini(this->node_ptr); + EXPECT_EQ(RCL_RET_OK, ret) << rcl_get_error_string().str; }); ASSERT_TRUE(wait_for_server_to_be_available(this->node_ptr, &client, 10, 1000)); @@ -283,6 +340,9 @@ TEST_F( const rosidl_service_type_support_t * ts = ROSIDL_GET_SRV_TYPE_SUPPORT( type_description_interfaces, srv, GetTypeDescription); + // Create type description service. + EXPECT_EQ(RCL_RET_OK, rcl_node_type_description_service_init(this->node_ptr)); + // Create client. rcl_client_t client = rcl_get_zero_initialized_client(); rcl_client_options_t client_options = rcl_client_get_default_options(); @@ -294,6 +354,9 @@ TEST_F( { rcl_ret_t ret = rcl_client_fini(&client, this->node_ptr); EXPECT_EQ(RCL_RET_OK, ret) << rcl_get_error_string().str; + + ret = rcl_node_type_description_service_fini(this->node_ptr); + EXPECT_EQ(RCL_RET_OK, ret) << rcl_get_error_string().str; }); ASSERT_TRUE(wait_for_server_to_be_available(this->node_ptr, &client, 10, 1000));