Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
10 changes: 10 additions & 0 deletions rcl_lifecycle/CMakeLists.txt
Original file line number Diff line number Diff line change
Expand Up @@ -56,6 +56,10 @@ rcl_set_symbol_visibility_hidden(${PROJECT_NAME} LANGUAGE "C")
# which is appropriate when building the dll but not consuming it.
target_compile_definitions(rcl_lifecycle PRIVATE "RCL_LIFECYCLE_BUILDING_DLL")

if(BUILD_TESTING AND NOT RCUTILS_DISABLE_FAULT_INJECTION)
target_compile_definitions(${PROJECT_NAME} PUBLIC RCUTILS_ENABLE_FAULT_INJECTION)
endif()

install(TARGETS rcl_lifecycle EXPORT rcl_lifecycle
ARCHIVE DESTINATION lib
LIBRARY DESTINATION lib
Expand All @@ -78,6 +82,9 @@ if(BUILD_TESTING)
"osrf_testing_tools_cpp"
)
target_link_libraries(test_default_state_machine ${PROJECT_NAME})
target_compile_definitions(test_default_state_machine
PUBLIC RCUTILS_ENABLE_FAULT_INJECTION
)
endif()
ament_add_gtest(test_multiple_instances
test/test_multiple_instances.cpp
Expand All @@ -98,6 +105,9 @@ if(BUILD_TESTING)
"osrf_testing_tools_cpp"
)
target_link_libraries(test_rcl_lifecycle ${PROJECT_NAME})
target_compile_definitions(test_rcl_lifecycle
PUBLIC RCUTILS_ENABLE_FAULT_INJECTION
)
endif()
ament_add_gtest(test_transition_map
test/test_transition_map.cpp
Expand Down
3 changes: 3 additions & 0 deletions rcl_lifecycle/src/rcl_lifecycle.c
Original file line number Diff line number Diff line change
Expand Up @@ -27,6 +27,7 @@ extern "C"
#include "rcl/error_handling.h"

#include "rcutils/logging_macros.h"
#include "rcutils/macros.h"
#include "rcutils/strdup.h"

#include "rcl_lifecycle/default_state_machine.h"
Expand Down Expand Up @@ -80,6 +81,8 @@ rcl_lifecycle_state_fini(
rcl_lifecycle_state_t * state,
const rcl_allocator_t * allocator)
{
RCUTILS_CAN_RETURN_WITH_ERROR_OF(RCL_RET_ERROR);

if (!allocator) {
RCL_SET_ERROR_MSG("can't free state, no allocator given\n");
return RCL_RET_ERROR;
Expand Down
7 changes: 7 additions & 0 deletions rcl_lifecycle/src/transition_map.c
Original file line number Diff line number Diff line change
Expand Up @@ -22,6 +22,7 @@ extern "C"
#include <string.h>

#include "rcl/error_handling.h"
#include "rcl/macros.h"
#include "rcutils/format_string.h"

#include "rcl_lifecycle/transition_map.h"
Expand Down Expand Up @@ -53,6 +54,7 @@ rcl_lifecycle_transition_map_fini(
rcl_lifecycle_transition_map_t * transition_map,
const rcutils_allocator_t * allocator)
{
RCUTILS_CAN_RETURN_WITH_ERROR_OF(RCL_RET_ERROR);
if (!allocator) {
RCL_SET_ERROR_MSG("can't free transition map, no allocator given\n");
return RCL_RET_ERROR;
Expand Down Expand Up @@ -85,6 +87,8 @@ rcl_lifecycle_register_state(
rcl_lifecycle_state_t state,
const rcutils_allocator_t * allocator)
{
RCUTILS_CAN_RETURN_WITH_ERROR_OF(RCL_RET_ERROR);

if (rcl_lifecycle_get_state(transition_map, state.id) != NULL) {
RCL_SET_ERROR_MSG_WITH_FORMAT_STRING("state %u is already registered\n", state.id);
return RCL_RET_ERROR;
Expand Down Expand Up @@ -116,6 +120,9 @@ rcl_lifecycle_register_transition(
rcl_lifecycle_transition_t transition,
const rcutils_allocator_t * allocator)
{
RCUTILS_CAN_RETURN_WITH_ERROR_OF(RCL_RET_ERROR);
RCUTILS_CAN_RETURN_WITH_ERROR_OF(RCL_RET_BAD_ALLOC);

RCUTILS_CHECK_ALLOCATOR_WITH_MSG(
allocator, "invalid allocator", return RCL_RET_ERROR)

Expand Down
17 changes: 17 additions & 0 deletions rcl_lifecycle/test/test_default_state_machine.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -28,6 +28,7 @@
#include "rcl/rcl.h"

#include "rcutils/logging_macros.h"
#include "rcutils/testing/fault_injection.h"

#include "rcl_lifecycle/rcl_lifecycle.h"
#include "rcl_lifecycle/default_state_machine.h"
Expand Down Expand Up @@ -833,3 +834,19 @@ TEST_F(TestDefaultStateMachine, default_sequence_error_unresolved) {
rcl_lifecycle_state_machine_fini(&state_machine, this->node_ptr, this->allocator));
}
}

TEST_F(TestDefaultStateMachine, init_fini_maybe_fail) {
rcl_lifecycle_state_machine_t sm = rcl_lifecycle_get_zero_initialized_state_machine();
RCUTILS_FAULT_INJECTION_TEST(
{
rcl_ret_t ret = rcl_lifecycle_init_default_state_machine(&sm, this->allocator);
if (RCL_RET_OK == ret) {
ret = rcl_lifecycle_state_machine_fini(&sm, this->node_ptr, this->allocator);
if (RCL_RET_OK != ret) {
EXPECT_EQ(
RCL_RET_OK,
rcl_lifecycle_state_machine_fini(&sm, this->node_ptr, this->allocator));
}
}
});
}
65 changes: 59 additions & 6 deletions rcl_lifecycle/test/test_rcl_lifecycle.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -19,9 +19,12 @@
#include <gtest/gtest.h>

#include "rcl_lifecycle/rcl_lifecycle.h"

#include "osrf_testing_tools_cpp/memory_tools/memory_tools.hpp"
#include "osrf_testing_tools_cpp/scope_exit.hpp"
#include "rcl/error_handling.h"
#include "rcutils/testing/fault_injection.h"

#include "lifecycle_msgs/msg/transition_event.h"
#include "lifecycle_msgs/srv/change_state.h"
#include "lifecycle_msgs/srv/get_available_states.h"
Expand Down Expand Up @@ -204,9 +207,9 @@ TEST(TestRclLifecycle, state_machine) {

OSRF_TESTING_TOOLS_CPP_SCOPE_EXIT(
{
ASSERT_EQ(RCL_RET_OK, rcl_node_fini(&node)) << rcl_get_error_string().str;
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;
EXPECT_EQ(RCL_RET_OK, rcl_node_fini(&node)) << rcl_get_error_string().str;
EXPECT_EQ(RCL_RET_OK, rcl_shutdown(&context)) << rcl_get_error_string().str;
EXPECT_EQ(RCL_RET_OK, rcl_context_fini(&context)) << rcl_get_error_string().str;
});

const rosidl_message_type_support_t * pn =
Expand Down Expand Up @@ -364,9 +367,9 @@ TEST(TestRclLifecycle, state_transitions) {

OSRF_TESTING_TOOLS_CPP_SCOPE_EXIT(
{
ASSERT_EQ(RCL_RET_OK, rcl_node_fini(&node)) << rcl_get_error_string().str;
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;
EXPECT_EQ(RCL_RET_OK, rcl_node_fini(&node)) << rcl_get_error_string().str;
EXPECT_EQ(RCL_RET_OK, rcl_shutdown(&context)) << rcl_get_error_string().str;
EXPECT_EQ(RCL_RET_OK, rcl_context_fini(&context)) << rcl_get_error_string().str;
});

const rosidl_message_type_support_t * pn =
Expand Down Expand Up @@ -436,3 +439,53 @@ TEST(TestRclLifecycle, state_transitions) {
ret = rcl_lifecycle_state_machine_fini(&state_machine, &node, &allocator);
EXPECT_EQ(ret, RCL_RET_OK) << rcl_get_error_string().str;
}

TEST(TestRclLifecycle, init_fini_maybe_fail) {
rcl_node_t node = rcl_get_zero_initialized_node();
rcl_allocator_t allocator = rcl_get_default_allocator();
rcl_context_t context = rcl_get_zero_initialized_context();
rcl_node_options_t options = rcl_node_get_default_options();
rcl_init_options_t init_options = rcl_get_zero_initialized_init_options();
rcl_ret_t ret = rcl_init_options_init(&init_options, allocator);
EXPECT_EQ(ret, RCL_RET_OK) << rcl_get_error_string().str;

ret = rcl_init(0, nullptr, &init_options, &context);
EXPECT_EQ(ret, RCL_RET_OK) << rcl_get_error_string().str;

OSRF_TESTING_TOOLS_CPP_SCOPE_EXIT(
{
EXPECT_EQ(RCL_RET_OK, rcl_shutdown(&context));
EXPECT_EQ(RCL_RET_OK, rcl_context_fini(&context));
});

ret = rcl_node_init(&node, "node", "namespace", &context, &options);
EXPECT_EQ(ret, RCL_RET_OK) << rcl_get_error_string().str;

const rosidl_message_type_support_t * pn =
ROSIDL_GET_MSG_TYPE_SUPPORT(lifecycle_msgs, msg, TransitionEvent);
const rosidl_service_type_support_t * cs =
ROSIDL_GET_SRV_TYPE_SUPPORT(lifecycle_msgs, srv, ChangeState);
const rosidl_service_type_support_t * gs =
ROSIDL_GET_SRV_TYPE_SUPPORT(lifecycle_msgs, srv, GetState);
const rosidl_service_type_support_t * gas =
ROSIDL_GET_SRV_TYPE_SUPPORT(lifecycle_msgs, srv, GetAvailableStates);
const rosidl_service_type_support_t * gat =
ROSIDL_GET_SRV_TYPE_SUPPORT(lifecycle_msgs, srv, GetAvailableTransitions);
const rosidl_service_type_support_t * gtg =
ROSIDL_GET_SRV_TYPE_SUPPORT(lifecycle_msgs, srv, GetAvailableTransitions);

RCUTILS_FAULT_INJECTION_TEST(
{
// Init segfaults if this is not zero initialized
rcl_lifecycle_state_machine_t sm = rcl_lifecycle_get_zero_initialized_state_machine();

ret = rcl_lifecycle_state_machine_init(
&sm, &node, pn, cs, gs, gas, gat, gtg, true, &allocator);
if (RCL_RET_OK == ret) {
ret = rcl_lifecycle_state_machine_fini(&sm, &node, &allocator);
if (RCL_RET_OK != ret) {
EXPECT_EQ(RCL_RET_OK, rcl_lifecycle_state_machine_fini(&sm, &node, &allocator));
}
}
});
}