Skip to content

Commit 0c9dfc5

Browse files
committed
Add fault injection macros to rcl functions
Signed-off-by: Stephen Brawner <brawner@gmail.com>
1 parent f90c01c commit 0c9dfc5

10 files changed

+115
-0
lines changed

rcl/CMakeLists.txt

+4
Original file line numberDiff line numberDiff line change
@@ -86,6 +86,10 @@ ament_target_dependencies(${PROJECT_NAME}
8686
target_compile_definitions(${PROJECT_NAME} PRIVATE "RCL_BUILDING_DLL")
8787
rcl_set_symbol_visibility_hidden(${PROJECT_NAME} LANGUAGE "C")
8888

89+
if(BUILD_TESTING AND NOT RCUTILS_DISABLE_FAULT_INJECTION)
90+
target_compile_definitions(${PROJECT_NAME} PUBLIC RCUTILS_ENABLE_FAULT_INJECTION)
91+
endif()
92+
8993
install(
9094
TARGETS ${PROJECT_NAME} EXPORT ${PROJECT_NAME}
9195
ARCHIVE DESTINATION lib

rcl/src/rcl/client.c

+5
Original file line numberDiff line numberDiff line change
@@ -26,6 +26,7 @@ extern "C"
2626
#include "rcl/expand_topic_name.h"
2727
#include "rcl/remap.h"
2828
#include "rcutils/logging_macros.h"
29+
#include "rcutils/macros.h"
2930
#include "rcutils/stdatomic_helper.h"
3031
#include "rmw/error_handling.h"
3132
#include "rmw/rmw.h"
@@ -206,6 +207,10 @@ rcl_client_init(
206207
rcl_ret_t
207208
rcl_client_fini(rcl_client_t * client, rcl_node_t * node)
208209
{
210+
RCUTILS_CAN_RETURN_WITH_ERROR_OF(RCL_RET_INVALID_ARGUMENT);
211+
RCUTILS_CAN_RETURN_WITH_ERROR_OF(RCL_RET_NODE_INVALID);
212+
RCUTILS_CAN_RETURN_WITH_ERROR_OF(RCL_RET_ERROR);
213+
209214
RCUTILS_LOG_DEBUG_NAMED(ROS_PACKAGE_NAME, "Finalizing client");
210215
rcl_ret_t result = RCL_RET_OK;
211216
RCL_CHECK_ARGUMENT_FOR_NULL(client, RCL_RET_INVALID_ARGUMENT);

rcl/src/rcl/graph.c

+8
Original file line numberDiff line numberDiff line change
@@ -21,6 +21,7 @@ extern "C"
2121

2222
#include "rcl/error_handling.h"
2323
#include "rcutils/allocator.h"
24+
#include "rcutils/macros.h"
2425
#include "rcutils/types.h"
2526
#include "rmw/error_handling.h"
2627
#include "rmw/get_node_info_and_types.h"
@@ -289,6 +290,8 @@ rcl_names_and_types_init(
289290
size_t size,
290291
rcl_allocator_t * allocator)
291292
{
293+
RCUTILS_CAN_RETURN_WITH_ERROR_OF(RCL_RET_INVALID_ARGUMENT);
294+
292295
RCL_CHECK_ARGUMENT_FOR_NULL(names_and_types, RCL_RET_INVALID_ARGUMENT);
293296
RCL_CHECK_ALLOCATOR(allocator, return RCL_RET_INVALID_ARGUMENT);
294297
rmw_ret_t rmw_ret = rmw_names_and_types_init(names_and_types, size, allocator);
@@ -298,6 +301,8 @@ rcl_names_and_types_init(
298301
rcl_ret_t
299302
rcl_names_and_types_fini(rcl_names_and_types_t * topic_names_and_types)
300303
{
304+
RCUTILS_CAN_RETURN_WITH_ERROR_OF(RCL_RET_INVALID_ARGUMENT);
305+
301306
RCL_CHECK_ARGUMENT_FOR_NULL(topic_names_and_types, RCL_RET_INVALID_ARGUMENT);
302307
rmw_ret_t rmw_ret = rmw_names_and_types_fini(topic_names_and_types);
303308
return rcl_convert_rmw_ret_to_rcl_ret(rmw_ret);
@@ -514,6 +519,9 @@ rcl_service_server_is_available(
514519
const rcl_client_t * client,
515520
bool * is_available)
516521
{
522+
RCUTILS_CAN_RETURN_WITH_ERROR_OF(RCL_RET_INVALID_ARGUMENT);
523+
RCUTILS_CAN_RETURN_WITH_ERROR_OF(RCL_RET_NODE_INVALID);
524+
517525
if (!rcl_node_is_valid(node)) {
518526
return RCL_RET_NODE_INVALID; // error already set
519527
}

rcl/src/rcl/publisher.c

+16
Original file line numberDiff line numberDiff line change
@@ -27,6 +27,7 @@ extern "C"
2727
#include "rcl/expand_topic_name.h"
2828
#include "rcl/remap.h"
2929
#include "rcutils/logging_macros.h"
30+
#include "rcutils/macros.h"
3031
#include "rmw/error_handling.h"
3132
#include "rmw/validate_full_topic_name.h"
3233
#include "tracetools/tracetools.h"
@@ -50,6 +51,13 @@ rcl_publisher_init(
5051
const rcl_publisher_options_t * options
5152
)
5253
{
54+
RCUTILS_CAN_RETURN_WITH_ERROR_OF(RCL_RET_INVALID_ARGUMENT);
55+
RCUTILS_CAN_RETURN_WITH_ERROR_OF(RCL_RET_ALREADY_INIT);
56+
RCUTILS_CAN_RETURN_WITH_ERROR_OF(RCL_RET_NODE_INVALID);
57+
RCUTILS_CAN_RETURN_WITH_ERROR_OF(RCL_RET_BAD_ALLOC);
58+
RCUTILS_CAN_RETURN_WITH_ERROR_OF(RCL_RET_ERROR);
59+
RCUTILS_CAN_RETURN_WITH_ERROR_OF(RCL_RET_TOPIC_NAME_INVALID);
60+
5361
rcl_ret_t fail_ret = RCL_RET_ERROR;
5462

5563
// Check options and allocator first, so allocator can be used with errors.
@@ -216,6 +224,11 @@ rcl_publisher_init(
216224
rcl_ret_t
217225
rcl_publisher_fini(rcl_publisher_t * publisher, rcl_node_t * node)
218226
{
227+
RCUTILS_CAN_RETURN_WITH_ERROR_OF(RCL_RET_PUBLISHER_INVALID);
228+
RCUTILS_CAN_RETURN_WITH_ERROR_OF(RCL_RET_NODE_INVALID);
229+
RCUTILS_CAN_RETURN_WITH_ERROR_OF(RCL_RET_INVALID_ARGUMENT);
230+
RCUTILS_CAN_RETURN_WITH_ERROR_OF(RCL_RET_ERROR);
231+
219232
rcl_ret_t result = RCL_RET_OK;
220233
RCL_CHECK_ARGUMENT_FOR_NULL(publisher, RCL_RET_PUBLISHER_INVALID);
221234
if (!rcl_node_is_valid_except_context(node)) {
@@ -286,6 +299,9 @@ rcl_publish(
286299
const void * ros_message,
287300
rmw_publisher_allocation_t * allocation)
288301
{
302+
RCUTILS_CAN_RETURN_WITH_ERROR_OF(RCL_RET_PUBLISHER_INVALID);
303+
RCUTILS_CAN_RETURN_WITH_ERROR_OF(RCL_RET_ERROR);
304+
289305
if (!rcl_publisher_is_valid(publisher)) {
290306
return RCL_RET_PUBLISHER_INVALID; // error already set
291307
}

rcl/src/rcl/service.c

+13
Original file line numberDiff line numberDiff line change
@@ -26,6 +26,7 @@ extern "C"
2626
#include "rcl/expand_topic_name.h"
2727
#include "rcl/remap.h"
2828
#include "rcutils/logging_macros.h"
29+
#include "rcutils/macros.h"
2930
#include "rmw/error_handling.h"
3031
#include "rmw/rmw.h"
3132
#include "rmw/validate_full_topic_name.h"
@@ -52,6 +53,13 @@ rcl_service_init(
5253
const char * service_name,
5354
const rcl_service_options_t * options)
5455
{
56+
RCUTILS_CAN_RETURN_WITH_ERROR_OF(RCL_RET_INVALID_ARGUMENT);
57+
RCUTILS_CAN_RETURN_WITH_ERROR_OF(RCL_RET_ALREADY_INIT);
58+
RCUTILS_CAN_RETURN_WITH_ERROR_OF(RCL_RET_NODE_INVALID);
59+
RCUTILS_CAN_RETURN_WITH_ERROR_OF(RCL_RET_BAD_ALLOC);
60+
RCUTILS_CAN_RETURN_WITH_ERROR_OF(RCL_RET_ERROR);
61+
RCUTILS_CAN_RETURN_WITH_ERROR_OF(RCL_RET_SERVICE_NAME_INVALID);
62+
5563
rcl_ret_t fail_ret = RCL_RET_ERROR;
5664

5765
// Check options and allocator first, so the allocator can be used in errors.
@@ -210,6 +218,11 @@ rcl_service_init(
210218
rcl_ret_t
211219
rcl_service_fini(rcl_service_t * service, rcl_node_t * node)
212220
{
221+
RCUTILS_CAN_RETURN_WITH_ERROR_OF(RCL_RET_SERVICE_INVALID);
222+
RCUTILS_CAN_RETURN_WITH_ERROR_OF(RCL_RET_NODE_INVALID);
223+
RCUTILS_CAN_RETURN_WITH_ERROR_OF(RCL_RET_INVALID_ARGUMENT);
224+
RCUTILS_CAN_RETURN_WITH_ERROR_OF(RCL_RET_ERROR);
225+
213226
RCUTILS_LOG_DEBUG_NAMED(ROS_PACKAGE_NAME, "Finalizing service");
214227
RCL_CHECK_ARGUMENT_FOR_NULL(service, RCL_RET_SERVICE_INVALID);
215228
if (!rcl_node_is_valid_except_context(node)) {

rcl/src/rcl/subscription.c

+11
Original file line numberDiff line numberDiff line change
@@ -193,6 +193,7 @@ rcl_subscription_init(
193193
goto cleanup;
194194
fail:
195195
if (subscription->impl) {
196+
subscription->impl->options.rmw_subscription_options.rmw_specific_subscription_payload = NULL;
196197
allocator->deallocate(subscription->impl, allocator->state);
197198
subscription->impl = NULL;
198199
}
@@ -211,6 +212,11 @@ rcl_subscription_init(
211212
rcl_ret_t
212213
rcl_subscription_fini(rcl_subscription_t * subscription, rcl_node_t * node)
213214
{
215+
RCUTILS_CAN_RETURN_WITH_ERROR_OF(RCL_RET_SUBSCRIPTION_INVALID);
216+
RCUTILS_CAN_RETURN_WITH_ERROR_OF(RCL_RET_NODE_INVALID);
217+
RCUTILS_CAN_RETURN_WITH_ERROR_OF(RCL_RET_INVALID_ARGUMENT);
218+
RCUTILS_CAN_RETURN_WITH_ERROR_OF(RCL_RET_ERROR);
219+
214220
RCUTILS_LOG_DEBUG_NAMED(ROS_PACKAGE_NAME, "Finalizing subscription");
215221
rcl_ret_t result = RCL_RET_OK;
216222
RCL_CHECK_ARGUMENT_FOR_NULL(subscription, RCL_RET_SUBSCRIPTION_INVALID);
@@ -229,6 +235,8 @@ rcl_subscription_fini(rcl_subscription_t * subscription, rcl_node_t * node)
229235
RCL_SET_ERROR_MSG(rmw_get_error_string().str);
230236
result = RCL_RET_ERROR;
231237
}
238+
subscription->impl->rmw_handle = NULL;
239+
232240
allocator.deallocate(subscription->impl, allocator.state);
233241
subscription->impl = NULL;
234242
}
@@ -457,6 +465,9 @@ rcl_subscription_get_publisher_count(
457465
const rcl_subscription_t * subscription,
458466
size_t * publisher_count)
459467
{
468+
RCUTILS_CAN_RETURN_WITH_ERROR_OF(RCL_RET_SUBSCRIPTION_INVALID);
469+
RCUTILS_CAN_RETURN_WITH_ERROR_OF(RCL_RET_INVALID_ARGUMENT);
470+
460471
if (!rcl_subscription_is_valid(subscription)) {
461472
return RCL_RET_SUBSCRIPTION_INVALID;
462473
}

rcl/src/rcl/time.c

+4
Original file line numberDiff line numberDiff line change
@@ -20,6 +20,7 @@
2020
#include "./common.h"
2121
#include "rcl/allocator.h"
2222
#include "rcl/error_handling.h"
23+
#include "rcutils/macros.h"
2324
#include "rcutils/stdatomic_helper.h"
2425
#include "rcutils/time.h"
2526

@@ -251,6 +252,9 @@ rcl_difference_times(
251252
rcl_ret_t
252253
rcl_clock_get_now(rcl_clock_t * clock, rcl_time_point_value_t * time_point_value)
253254
{
255+
RCUTILS_CAN_RETURN_WITH_ERROR_OF(RCL_RET_INVALID_ARGUMENT);
256+
RCUTILS_CAN_RETURN_WITH_ERROR_OF(RCL_RET_ERROR);
257+
254258
RCL_CHECK_ARGUMENT_FOR_NULL(clock, RCL_RET_INVALID_ARGUMENT);
255259
RCL_CHECK_ARGUMENT_FOR_NULL(time_point_value, RCL_RET_INVALID_ARGUMENT);
256260
if (clock->type && clock->get_now) {

rcl/src/rcl/timer.c

+7
Original file line numberDiff line numberDiff line change
@@ -345,6 +345,8 @@ rcl_timer_get_period(const rcl_timer_t * timer, int64_t * period)
345345
rcl_ret_t
346346
rcl_timer_exchange_period(const rcl_timer_t * timer, int64_t new_period, int64_t * old_period)
347347
{
348+
RCUTILS_CAN_RETURN_WITH_ERROR_OF(RCL_RET_INVALID_ARGUMENT);
349+
348350
RCL_CHECK_ARGUMENT_FOR_NULL(timer, RCL_RET_INVALID_ARGUMENT);
349351
RCL_CHECK_ARGUMENT_FOR_NULL(old_period, RCL_RET_INVALID_ARGUMENT);
350352
*old_period = rcutils_atomic_exchange_uint64_t(&timer->impl->period, new_period);
@@ -375,6 +377,9 @@ rcl_timer_exchange_callback(rcl_timer_t * timer, const rcl_timer_callback_t new_
375377
rcl_ret_t
376378
rcl_timer_cancel(rcl_timer_t * timer)
377379
{
380+
RCUTILS_CAN_RETURN_WITH_ERROR_OF(RCL_RET_INVALID_ARGUMENT);
381+
RCUTILS_CAN_RETURN_WITH_ERROR_OF(RCL_RET_TIMER_INVALID);
382+
378383
RCL_CHECK_ARGUMENT_FOR_NULL(timer, RCL_RET_INVALID_ARGUMENT);
379384
RCL_CHECK_FOR_NULL_WITH_MSG(timer->impl, "timer is invalid", return RCL_RET_TIMER_INVALID);
380385
rcutils_atomic_store(&timer->impl->canceled, true);
@@ -394,6 +399,8 @@ rcl_timer_is_canceled(const rcl_timer_t * timer, bool * is_canceled)
394399
rcl_ret_t
395400
rcl_timer_reset(rcl_timer_t * timer)
396401
{
402+
RCUTILS_CAN_RETURN_WITH_ERROR_OF(RCL_RET_INVALID_ARGUMENT);
403+
397404
RCL_CHECK_ARGUMENT_FOR_NULL(timer, RCL_RET_INVALID_ARGUMENT);
398405
RCL_CHECK_FOR_NULL_WITH_MSG(timer->impl, "timer is invalid", return RCL_RET_TIMER_INVALID);
399406
rcl_time_point_value_t now;

rcl/test/rcl/test_client.cpp

+23
Original file line numberDiff line numberDiff line change
@@ -17,6 +17,7 @@
1717
#include "rcl/client.h"
1818

1919
#include "rcl/rcl.h"
20+
#include "rcutils/testing/fault_injection.h"
2021

2122
#include "test_msgs/srv/basic_types.h"
2223

@@ -277,3 +278,25 @@ TEST_F(TestClientFixture, test_client_bad_arguments) {
277278
&client, &client_request, &sequence_number)) << rcl_get_error_string().str;
278279
EXPECT_EQ(24, sequence_number);
279280
}
281+
282+
TEST_F(TestClientFixture, test_client_init_fini_maybe_fail)
283+
{
284+
const rosidl_service_type_support_t * ts = ROSIDL_GET_SRV_TYPE_SUPPORT(
285+
test_msgs, srv, BasicTypes);
286+
constexpr char topic_name[] = "chatter";
287+
rcl_client_options_t default_client_options = rcl_client_get_default_options();
288+
289+
RCUTILS_FAULT_INJECTION_TEST(
290+
{
291+
rcl_client_t client = rcl_get_zero_initialized_client();
292+
rcl_ret_t ret = rcl_client_init(
293+
&client, this->node_ptr, ts, topic_name, &default_client_options);
294+
if (RCL_RET_OK == ret) {
295+
EXPECT_TRUE(rcl_client_is_valid(&client));
296+
ret = rcl_client_fini(&client, this->node_ptr);
297+
} else {
298+
EXPECT_TRUE(rcl_error_is_set());
299+
rcl_reset_error();
300+
}
301+
});
302+
}

rcl/test/rcl/test_subscription.cpp

+24
Original file line numberDiff line numberDiff line change
@@ -23,6 +23,7 @@
2323
#include "rmw/rmw.h"
2424
#include "rmw/validate_full_topic_name.h"
2525

26+
#include "rcutils/testing/fault_injection.h"
2627
#include "test_msgs/msg/basic_types.h"
2728
#include "test_msgs/msg/strings.h"
2829
#include "rosidl_runtime_c/string_functions.h"
@@ -1065,3 +1066,26 @@ TEST_F(CLASSNAME(TestSubscriptionFixtureInit, RMW_IMPLEMENTATION), test_subscrip
10651066
EXPECT_EQ(NULL, rcl_subscription_get_options(&subscription_zero_init));
10661067
rcl_reset_error();
10671068
}
1069+
1070+
TEST_F(CLASSNAME(TestSubscriptionFixture, RMW_IMPLEMENTATION), test_init_fini_maybe_fail)
1071+
{
1072+
const rosidl_message_type_support_t * ts =
1073+
ROSIDL_GET_MSG_TYPE_SUPPORT(test_msgs, msg, BasicTypes);
1074+
constexpr char topic[] = "chatter";
1075+
rcl_subscription_options_t subscription_options = rcl_subscription_get_default_options();
1076+
rcl_subscription_t subscription = rcl_get_zero_initialized_subscription();
1077+
1078+
RCUTILS_FAULT_INJECTION_TEST(
1079+
{
1080+
rcl_ret_t ret = rcl_subscription_init(
1081+
&subscription, this->node_ptr, ts, topic, &subscription_options);
1082+
1083+
if (RCL_RET_OK == ret) {
1084+
EXPECT_TRUE(rcl_subscription_is_valid(&subscription));
1085+
ret = rcl_subscription_fini(&subscription, this->node_ptr);
1086+
} else {
1087+
EXPECT_TRUE(rcl_error_is_set());
1088+
rcl_reset_error();
1089+
}
1090+
});
1091+
}

0 commit comments

Comments
 (0)