Skip to content

Commit f8749e9

Browse files
committed
add get_type_description test
Signed-off-by: Hans-Joachim Krauch <[email protected]>
1 parent 13e4c7e commit f8749e9

File tree

2 files changed

+327
-0
lines changed

2 files changed

+327
-0
lines changed

rcl/test/CMakeLists.txt

Lines changed: 9 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -341,6 +341,15 @@ function(test_target_function)
341341
AMENT_DEPENDENCIES ${rmw_implementation} "osrf_testing_tools_cpp" "test_msgs"
342342
)
343343

344+
rcl_add_custom_gtest(test_get_type_description_service${target_suffix}
345+
SRCS rcl/test_get_type_description_service.cpp
346+
ENV ${rmw_implementation_env_var}
347+
APPEND_LIBRARY_DIRS ${extra_lib_dirs}
348+
INCLUDE_DIRS ${CMAKE_CURRENT_SOURCE_DIR}/../src/rcl/
349+
LIBRARIES ${PROJECT_NAME} mimick wait_for_entity_helpers
350+
AMENT_DEPENDENCIES ${rmw_implementation} "osrf_testing_tools_cpp" "type_description_interfaces"
351+
)
352+
344353
# Launch tests
345354

346355
rcl_add_custom_executable(service_fixture${target_suffix}
Lines changed: 318 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,318 @@
1+
// Copyright 2023 Open Source Robotics Foundation, Inc.
2+
//
3+
// Licensed under the Apache License, Version 2.0 (the "License");
4+
// you may not use this file except in compliance with the License.
5+
// You may obtain a copy of the License at
6+
//
7+
// http://www.apache.org/licenses/LICENSE-2.0
8+
//
9+
// Unless required by applicable law or agreed to in writing, software
10+
// distributed under the License is distributed on an "AS IS" BASIS,
11+
// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
12+
// See the License for the specific language governing permissions and
13+
// limitations under the License.
14+
15+
#include <gtest/gtest.h>
16+
17+
#include "rcl/error_handling.h"
18+
#include "rcl/graph.h"
19+
#include "rcl/service.h"
20+
#include "rcl/rcl.h"
21+
22+
#include "osrf_testing_tools_cpp/scope_exit.hpp"
23+
#include "rosidl_runtime_c/string_functions.h"
24+
#include "type_description_interfaces/srv/get_type_description.h"
25+
#include "wait_for_entity_helpers.hpp"
26+
27+
#ifdef RMW_IMPLEMENTATION
28+
# define CLASSNAME_(NAME, SUFFIX) NAME ## __ ## SUFFIX
29+
# define CLASSNAME(NAME, SUFFIX) CLASSNAME_(NAME, SUFFIX)
30+
#else
31+
# define CLASSNAME(NAME, SUFFIX) NAME
32+
#endif
33+
34+
constexpr char GET_TYPE_DESCRIPTION_SRV_TYPE_NAME[] =
35+
"type_description_interfaces/srv/GetTypeDescription";
36+
37+
static bool string_in_array(rcutils_string_array_t * array, const char * pattern)
38+
{
39+
for (size_t i = 0; i < array->size; ++i) {
40+
if (strcmp(array->data[i], pattern) == 0) {
41+
return true;
42+
}
43+
}
44+
return false;
45+
}
46+
47+
static bool service_exists(
48+
const rcl_node_t * node_ptr, const char * service_name,
49+
const char * service_type)
50+
{
51+
rcl_allocator_t allocator = rcl_get_default_allocator();
52+
53+
rcl_names_and_types_t * srv_names_and_types =
54+
static_cast<rcl_names_and_types_t *>(allocator.allocate(
55+
sizeof(rcl_names_and_types_t),
56+
allocator.state));
57+
if (nullptr == srv_names_and_types) {
58+
return false;
59+
}
60+
EXPECT_EQ(RCL_RET_OK, rcl_names_and_types_init(srv_names_and_types, 0, &allocator));
61+
srv_names_and_types->names.data = NULL;
62+
srv_names_and_types->names.size = 0;
63+
srv_names_and_types->types = NULL;
64+
65+
OSRF_TESTING_TOOLS_CPP_SCOPE_EXIT(
66+
{
67+
EXPECT_EQ(RCL_RET_OK, rcl_names_and_types_fini(srv_names_and_types));
68+
allocator.deallocate(srv_names_and_types, allocator.state);
69+
});
70+
71+
if (
72+
RCL_RET_OK != rcl_get_service_names_and_types(
73+
node_ptr,
74+
&allocator, srv_names_and_types))
75+
{
76+
return false;
77+
}
78+
79+
if (srv_names_and_types->names.size < 1) {
80+
return false;
81+
}
82+
83+
const bool srv_name_found = string_in_array(
84+
&srv_names_and_types->names,
85+
service_name);
86+
87+
if (!srv_name_found) {return false;}
88+
89+
bool type_name_found = false;
90+
for (size_t i = 0; i < srv_names_and_types->names.size; ++i) {
91+
type_name_found = string_in_array(
92+
&srv_names_and_types->types[i],
93+
service_type);
94+
if (type_name_found) {
95+
break;
96+
}
97+
}
98+
99+
return type_name_found;
100+
}
101+
102+
class CLASSNAME (TestGetTypeDescSrvEnabledFixture, RMW_IMPLEMENTATION) : public ::testing::Test
103+
{
104+
public:
105+
rcl_context_t * context_ptr;
106+
rcl_node_t * node_ptr;
107+
char get_type_description_service_name[256];
108+
bool enable_get_type_description_service;
109+
110+
virtual bool get_type_description_service_enabled() const
111+
{
112+
return true;
113+
}
114+
115+
void SetUp()
116+
{
117+
rcl_ret_t ret;
118+
{
119+
rcl_init_options_t init_options = rcl_get_zero_initialized_init_options();
120+
ret = rcl_init_options_init(&init_options, rcl_get_default_allocator());
121+
ASSERT_EQ(RCL_RET_OK, ret) << rcl_get_error_string().str;
122+
OSRF_TESTING_TOOLS_CPP_SCOPE_EXIT(
123+
{
124+
EXPECT_EQ(RCL_RET_OK, rcl_init_options_fini(&init_options)) << rcl_get_error_string().str;
125+
});
126+
this->context_ptr = new rcl_context_t;
127+
*this->context_ptr = rcl_get_zero_initialized_context();
128+
ret = rcl_init(0, nullptr, &init_options, this->context_ptr);
129+
ASSERT_EQ(RCL_RET_OK, ret) << rcl_get_error_string().str;
130+
}
131+
this->node_ptr = new rcl_node_t;
132+
*this->node_ptr = rcl_get_zero_initialized_node();
133+
const char * name = "test_service_node";
134+
rcl_node_options_t node_options = rcl_node_get_default_options();
135+
node_options.enable_type_description_service = get_type_description_service_enabled();
136+
ret = rcl_node_init(this->node_ptr, name, "", this->context_ptr, &node_options);
137+
ASSERT_EQ(RCL_RET_OK, ret) << rcl_get_error_string().str;
138+
139+
const char * node_fqn = rcl_node_get_fully_qualified_name(this->node_ptr);
140+
snprintf(
141+
get_type_description_service_name, sizeof(get_type_description_service_name),
142+
"%s/get_type_description", node_fqn);
143+
}
144+
145+
void TearDown()
146+
{
147+
rcl_ret_t ret = rcl_node_fini(this->node_ptr);
148+
delete this->node_ptr;
149+
EXPECT_EQ(RCL_RET_OK, ret) << rcl_get_error_string().str;
150+
ret = rcl_shutdown(this->context_ptr);
151+
EXPECT_EQ(RCL_RET_OK, ret) << rcl_get_error_string().str;
152+
ret = rcl_context_fini(this->context_ptr);
153+
delete this->context_ptr;
154+
EXPECT_EQ(RCL_RET_OK, ret) << rcl_get_error_string().str;
155+
}
156+
};
157+
158+
class CLASSNAME (TestGetTypeDescSrvDisabledFixture,
159+
RMW_IMPLEMENTATION) : public CLASSNAME(TestGetTypeDescSrvEnabledFixture, RMW_IMPLEMENTATION) {
160+
bool get_type_description_service_enabled() const override
161+
{
162+
return false;
163+
}
164+
};
165+
166+
/* Test service being enabled with node_options. */
167+
TEST_F(
168+
CLASSNAME(TestGetTypeDescSrvEnabledFixture, RMW_IMPLEMENTATION),
169+
test_service_existence_node_options_default) {
170+
EXPECT_TRUE(
171+
service_exists(
172+
this->node_ptr, this->get_type_description_service_name,
173+
GET_TYPE_DESCRIPTION_SRV_TYPE_NAME));
174+
}
175+
176+
/* Test service being disabled with node_options. */
177+
TEST_F(
178+
CLASSNAME(TestGetTypeDescSrvDisabledFixture, RMW_IMPLEMENTATION),
179+
test_service_existence_node_options_disabled) {
180+
EXPECT_FALSE(
181+
service_exists(
182+
this->node_ptr, this->get_type_description_service_name,
183+
GET_TYPE_DESCRIPTION_SRV_TYPE_NAME));
184+
}
185+
186+
/* Test init and fini functions. */
187+
TEST_F(
188+
CLASSNAME(TestGetTypeDescSrvEnabledFixture, RMW_IMPLEMENTATION),
189+
test_service_init_and_fini_functions) {
190+
EXPECT_TRUE(
191+
service_exists(
192+
this->node_ptr, this->get_type_description_service_name,
193+
GET_TYPE_DESCRIPTION_SRV_TYPE_NAME));
194+
EXPECT_EQ(RCL_RET_OK, rcl_node_type_description_service_fini(this->node_ptr));
195+
EXPECT_FALSE(
196+
service_exists(
197+
this->node_ptr, this->get_type_description_service_name,
198+
GET_TYPE_DESCRIPTION_SRV_TYPE_NAME));
199+
EXPECT_EQ(RCL_RET_NOT_INIT, rcl_node_type_description_service_fini(this->node_ptr));
200+
201+
EXPECT_EQ(RCL_RET_OK, rcl_node_type_description_service_init(this->node_ptr));
202+
EXPECT_TRUE(
203+
service_exists(
204+
this->node_ptr, this->get_type_description_service_name,
205+
GET_TYPE_DESCRIPTION_SRV_TYPE_NAME));
206+
EXPECT_EQ(RCL_RET_ALREADY_INIT, rcl_node_type_description_service_init(this->node_ptr));
207+
}
208+
209+
/* Basic nominal test of the ~/get_type_description service. */
210+
TEST_F(CLASSNAME(TestGetTypeDescSrvEnabledFixture, RMW_IMPLEMENTATION), test_service_nominal) {
211+
rcl_ret_t ret;
212+
const rosidl_service_type_support_t * ts = ROSIDL_GET_SRV_TYPE_SUPPORT(
213+
type_description_interfaces, srv, GetTypeDescription);
214+
215+
// Create client.
216+
rcl_client_t client = rcl_get_zero_initialized_client();
217+
rcl_client_options_t client_options = rcl_client_get_default_options();
218+
ret = rcl_client_init(
219+
&client, this->node_ptr, ts, this->get_type_description_service_name,
220+
&client_options);
221+
ASSERT_EQ(RCL_RET_OK, ret) << rcl_get_error_string().str;
222+
OSRF_TESTING_TOOLS_CPP_SCOPE_EXIT(
223+
{
224+
rcl_ret_t ret = rcl_client_fini(&client, this->node_ptr);
225+
EXPECT_EQ(RCL_RET_OK, ret) << rcl_get_error_string().str;
226+
});
227+
ASSERT_TRUE(wait_for_server_to_be_available(this->node_ptr, &client, 10, 1000));
228+
229+
// Initialize a request.
230+
type_description_interfaces__srv__GetTypeDescription_Request client_request;
231+
type_description_interfaces__srv__GetTypeDescription_Request__init(&client_request);
232+
233+
// Fill the request. We use the GetTypeDescription hash because we know that that type
234+
// is registered.
235+
const rosidl_type_hash_t * type_hash = ts->get_type_hash_func(ts);
236+
rcutils_allocator_t allocator = rcutils_get_default_allocator();
237+
char * type_hash_str;
238+
EXPECT_EQ(RCUTILS_RET_OK, rosidl_stringify_type_hash(type_hash, allocator, &type_hash_str));
239+
OSRF_TESTING_TOOLS_CPP_SCOPE_EXIT(
240+
{
241+
allocator.deallocate(type_hash_str, allocator.state);
242+
});
243+
rosidl_runtime_c__String__assign(&client_request.type_hash, type_hash_str);
244+
rosidl_runtime_c__String__assign(&client_request.type_name, GET_TYPE_DESCRIPTION_SRV_TYPE_NAME);
245+
client_request.include_type_sources = true;
246+
247+
// Send the request.
248+
int64_t sequence_number;
249+
ret = rcl_send_request(&client, &client_request, &sequence_number);
250+
type_description_interfaces__srv__GetTypeDescription_Request__fini(&client_request);
251+
ASSERT_EQ(RCL_RET_OK, ret) << rcl_get_error_string().str;
252+
253+
// Initialize the response owned by the client and take the response.
254+
type_description_interfaces__srv__GetTypeDescription_Response client_response;
255+
type_description_interfaces__srv__GetTypeDescription_Response__init(&client_response);
256+
257+
// Retrieve the response.
258+
rmw_service_info_t header;
259+
ret = rcl_take_response_with_info(&client, &header, &client_response);
260+
ASSERT_EQ(RCL_RET_OK, ret) << rcl_get_error_string().str;
261+
EXPECT_EQ(client_response.successful, true);
262+
EXPECT_EQ(sequence_number, header.request_id.sequence_number);
263+
264+
type_description_interfaces__srv__GetTypeDescription_Response__fini(&client_response);
265+
}
266+
267+
/* Test calling ~/get_type_description service with invalid hash service. */
268+
TEST_F(
269+
CLASSNAME(
270+
TestGetTypeDescSrvEnabledFixture,
271+
RMW_IMPLEMENTATION), test_service_invalid_hash) {
272+
rcl_ret_t ret;
273+
const rosidl_service_type_support_t * ts = ROSIDL_GET_SRV_TYPE_SUPPORT(
274+
type_description_interfaces, srv, GetTypeDescription);
275+
276+
// Create client.
277+
rcl_client_t client = rcl_get_zero_initialized_client();
278+
rcl_client_options_t client_options = rcl_client_get_default_options();
279+
ret = rcl_client_init(
280+
&client, this->node_ptr, ts, this->get_type_description_service_name,
281+
&client_options);
282+
ASSERT_EQ(RCL_RET_OK, ret) << rcl_get_error_string().str;
283+
OSRF_TESTING_TOOLS_CPP_SCOPE_EXIT(
284+
{
285+
rcl_ret_t ret = rcl_client_fini(&client, this->node_ptr);
286+
EXPECT_EQ(RCL_RET_OK, ret) << rcl_get_error_string().str;
287+
});
288+
ASSERT_TRUE(wait_for_server_to_be_available(this->node_ptr, &client, 10, 1000));
289+
290+
// Initialize a request.
291+
type_description_interfaces__srv__GetTypeDescription_Request client_request;
292+
type_description_interfaces__srv__GetTypeDescription_Request__init(&client_request);
293+
294+
// Fill the request.
295+
rosidl_runtime_c__String__assign(&client_request.type_hash, "foo");
296+
rosidl_runtime_c__String__assign(&client_request.type_name, "bar");
297+
client_request.include_type_sources = true;
298+
299+
// Send the request.
300+
int64_t sequence_number;
301+
ret = rcl_send_request(&client, &client_request, &sequence_number);
302+
type_description_interfaces__srv__GetTypeDescription_Request__fini(&client_request);
303+
ASSERT_EQ(RCL_RET_OK, ret) << rcl_get_error_string().str;
304+
305+
// Initialize the response owned by the client and take the response.
306+
type_description_interfaces__srv__GetTypeDescription_Response client_response;
307+
type_description_interfaces__srv__GetTypeDescription_Response__init(&client_response);
308+
309+
// Retrieve the response.
310+
rmw_service_info_t header;
311+
ret = rcl_take_response_with_info(&client, &header, &client_response);
312+
ASSERT_EQ(RCL_RET_OK, ret) << rcl_get_error_string().str;
313+
EXPECT_EQ(client_response.successful, false);
314+
EXPECT_GT(strlen(client_response.failure_reason.data), 0);
315+
EXPECT_EQ(sequence_number, header.request_id.sequence_number);
316+
317+
type_description_interfaces__srv__GetTypeDescription_Response__fini(&client_response);
318+
}

0 commit comments

Comments
 (0)