[rcl_action] Add function to check if goal can be transitioned to CANCELING (#325)
* [rcl_action] Add function for checking if goal can be transitioned to CANCELING Add unit tests for the new function rcl_action_goal_handle_is_cancelable(), as well as rcl_action_goal_handle_is_active().
This commit is contained in:
parent
9351fd89c7
commit
8b00791a56
3 changed files with 88 additions and 45 deletions
|
@ -202,15 +202,37 @@ rcl_action_goal_handle_get_status(
|
||||||
* Lock-Free | Yes
|
* Lock-Free | Yes
|
||||||
*
|
*
|
||||||
* \param[in] goal_handle struct containing the goal and metadata
|
* \param[in] goal_handle struct containing the goal and metadata
|
||||||
* \return `true` if a goal is in one of the following states: ACCEPTED, EXECUTING, or CANCELING, or
|
* \return `true` if the goal is in one of the following states: ACCEPTED, EXECUTING, or CANCELING, or
|
||||||
* \return `false` otherwise, also
|
* \return `false` if the goal handle pointer is invalid, or
|
||||||
* \return `false` if the goal handle pointer is invalid
|
* \return `false` otherwise
|
||||||
*/
|
*/
|
||||||
RCL_ACTION_PUBLIC
|
RCL_ACTION_PUBLIC
|
||||||
RCL_WARN_UNUSED
|
RCL_WARN_UNUSED
|
||||||
bool
|
bool
|
||||||
rcl_action_goal_handle_is_active(const rcl_action_goal_handle_t * goal_handle);
|
rcl_action_goal_handle_is_active(const rcl_action_goal_handle_t * goal_handle);
|
||||||
|
|
||||||
|
/// Check if a goal can be transitioned to CANCELING in its current state.
|
||||||
|
/**
|
||||||
|
* This is a non-blocking call.
|
||||||
|
*
|
||||||
|
* <hr>
|
||||||
|
* Attribute | Adherence
|
||||||
|
* ------------------ | -------------
|
||||||
|
* Allocates Memory | No
|
||||||
|
* Thread-Safe | No
|
||||||
|
* Uses Atomics | No
|
||||||
|
* Lock-Free | Yes
|
||||||
|
*
|
||||||
|
* \param[in] goal_handle struct containing the goal and metadata
|
||||||
|
* \return `true` if the goal can be transitioned to CANCELING from its current state, or
|
||||||
|
* \return `false` if the goal handle pointer is invalid, or
|
||||||
|
* \return `false` otherwise
|
||||||
|
*/
|
||||||
|
RCL_ACTION_PUBLIC
|
||||||
|
RCL_WARN_UNUSED
|
||||||
|
bool
|
||||||
|
rcl_action_goal_handle_is_cancelable(const rcl_action_goal_handle_t * goal_handle);
|
||||||
|
|
||||||
/// Check if a rcl_action_goal_handle_t is valid.
|
/// Check if a rcl_action_goal_handle_t is valid.
|
||||||
/**
|
/**
|
||||||
* This is a non-blocking call.
|
* This is a non-blocking call.
|
||||||
|
@ -229,8 +251,9 @@ rcl_action_goal_handle_is_active(const rcl_action_goal_handle_t * goal_handle);
|
||||||
* Lock-Free | Yes
|
* Lock-Free | Yes
|
||||||
*
|
*
|
||||||
* \param[in] goal_handle struct to evaluate as valid or not
|
* \param[in] goal_handle struct to evaluate as valid or not
|
||||||
* \return `true` if the goal handle is valid, `false` otherwise, also
|
* \return `true` if the goal handle is valid, or
|
||||||
* \return `false` if the goal handle pointer is null
|
* \return `false` if the goal handle pointer is null, or
|
||||||
|
* \return `false` otherwise
|
||||||
*/
|
*/
|
||||||
RCL_ACTION_PUBLIC
|
RCL_ACTION_PUBLIC
|
||||||
RCL_WARN_UNUSED
|
RCL_WARN_UNUSED
|
||||||
|
|
|
@ -137,6 +137,18 @@ rcl_action_goal_handle_is_active(const rcl_action_goal_handle_t * goal_handle)
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
bool
|
||||||
|
rcl_action_goal_handle_is_cancelable(const rcl_action_goal_handle_t * goal_handle)
|
||||||
|
{
|
||||||
|
if (!rcl_action_goal_handle_is_valid(goal_handle)) {
|
||||||
|
return false; // error message is set
|
||||||
|
}
|
||||||
|
// Check if the state machine reports a cancel event is valid
|
||||||
|
rcl_action_goal_state_t state = rcl_action_transition_goal_state(
|
||||||
|
goal_handle->impl->state, GOAL_EVENT_CANCEL);
|
||||||
|
return GOAL_STATE_CANCELING == state;
|
||||||
|
}
|
||||||
|
|
||||||
bool
|
bool
|
||||||
rcl_action_goal_handle_is_valid(const rcl_action_goal_handle_t * goal_handle)
|
rcl_action_goal_handle_is_valid(const rcl_action_goal_handle_t * goal_handle)
|
||||||
{
|
{
|
||||||
|
|
|
@ -15,7 +15,7 @@
|
||||||
|
|
||||||
#include <sstream>
|
#include <sstream>
|
||||||
#include <string>
|
#include <string>
|
||||||
#include <utility>
|
#include <tuple>
|
||||||
#include <vector>
|
#include <vector>
|
||||||
|
|
||||||
#include "rcl_action/goal_handle.h"
|
#include "rcl_action/goal_handle.h"
|
||||||
|
@ -156,8 +156,9 @@ TEST(TestGoalHandle, test_goal_handle_update_state_invalid)
|
||||||
rcl_reset_error();
|
rcl_reset_error();
|
||||||
}
|
}
|
||||||
|
|
||||||
using EventStatePair = std::pair<rcl_action_goal_event_t, rcl_action_goal_state_t>;
|
using EventStateActiveCancelableTuple =
|
||||||
using StateTransitionSequence = std::vector<EventStatePair>;
|
std::tuple<rcl_action_goal_event_t, rcl_action_goal_state_t, bool, bool>;
|
||||||
|
using StateTransitionSequence = std::vector<EventStateActiveCancelableTuple>;
|
||||||
const std::vector<std::string> event_strs = {
|
const std::vector<std::string> event_strs = {
|
||||||
"EXECUTE", "CANCEL", "SET_SUCCEEDED", "SET_ABORTED", "SET_CANCELED"};
|
"EXECUTE", "CANCEL", "SET_SUCCEEDED", "SET_ABORTED", "SET_CANCELED"};
|
||||||
|
|
||||||
|
@ -169,8 +170,8 @@ public:
|
||||||
const testing::TestParamInfo<StateTransitionSequence> & info)
|
const testing::TestParamInfo<StateTransitionSequence> & info)
|
||||||
{
|
{
|
||||||
std::stringstream result;
|
std::stringstream result;
|
||||||
for (const EventStatePair & event_state : info.param) {
|
for (const EventStateActiveCancelableTuple & event_state : info.param) {
|
||||||
result << "_" << event_strs[event_state.first];
|
result << "_" << event_strs[std::get<0>(event_state)];
|
||||||
}
|
}
|
||||||
return result.str();
|
return result.str();
|
||||||
}
|
}
|
||||||
|
@ -216,15 +217,22 @@ TEST_P(TestGoalHandleStateTransitionSequence, test_goal_handle_state_transitions
|
||||||
|
|
||||||
// Walk through state transitions
|
// Walk through state transitions
|
||||||
rcl_ret_t ret;
|
rcl_ret_t ret;
|
||||||
for (const EventStatePair & event_state : this->test_sequence) {
|
for (const EventStateActiveCancelableTuple & event_state : this->test_sequence) {
|
||||||
ret = rcl_action_update_goal_state(&this->goal_handle, event_state.first);
|
rcl_action_goal_event_t goal_event;
|
||||||
const rcl_action_goal_state_t & expected_state = event_state.second;
|
rcl_action_goal_state_t expected_goal_state;
|
||||||
if (GOAL_STATE_UNKNOWN == expected_state) {
|
bool expected_is_active;
|
||||||
|
bool expected_is_cancelable;
|
||||||
|
std::tie(goal_event, expected_goal_state, expected_is_active, expected_is_cancelable) =
|
||||||
|
event_state;
|
||||||
|
ret = rcl_action_update_goal_state(&this->goal_handle, goal_event);
|
||||||
|
if (GOAL_STATE_UNKNOWN == expected_goal_state) {
|
||||||
EXPECT_EQ(ret, RCL_RET_ACTION_GOAL_EVENT_INVALID);
|
EXPECT_EQ(ret, RCL_RET_ACTION_GOAL_EVENT_INVALID);
|
||||||
continue;
|
continue;
|
||||||
}
|
}
|
||||||
EXPECT_EQ(ret, RCL_RET_OK);
|
EXPECT_EQ(ret, RCL_RET_OK);
|
||||||
expect_state_eq(expected_state);
|
expect_state_eq(expected_goal_state);
|
||||||
|
EXPECT_EQ(expected_is_active, rcl_action_goal_handle_is_active(&this->goal_handle));
|
||||||
|
EXPECT_EQ(expected_is_cancelable, rcl_action_goal_handle_is_cancelable(&this->goal_handle));
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -232,40 +240,40 @@ TEST_P(TestGoalHandleStateTransitionSequence, test_goal_handle_state_transitions
|
||||||
// Note, each sequence starts in the ACCEPTED state
|
// Note, each sequence starts in the ACCEPTED state
|
||||||
const StateTransitionSequence valid_state_transition_sequences[] = {
|
const StateTransitionSequence valid_state_transition_sequences[] = {
|
||||||
{
|
{
|
||||||
{GOAL_EVENT_EXECUTE, GOAL_STATE_EXECUTING},
|
std::make_tuple(GOAL_EVENT_EXECUTE, GOAL_STATE_EXECUTING, true, true),
|
||||||
{GOAL_EVENT_CANCEL, GOAL_STATE_CANCELING},
|
std::make_tuple(GOAL_EVENT_CANCEL, GOAL_STATE_CANCELING, true, false),
|
||||||
{GOAL_EVENT_SET_CANCELED, GOAL_STATE_CANCELED},
|
std::make_tuple(GOAL_EVENT_SET_CANCELED, GOAL_STATE_CANCELED, false, false),
|
||||||
},
|
},
|
||||||
{
|
{
|
||||||
{GOAL_EVENT_EXECUTE, GOAL_STATE_EXECUTING},
|
std::make_tuple(GOAL_EVENT_EXECUTE, GOAL_STATE_EXECUTING, true, true),
|
||||||
{GOAL_EVENT_CANCEL, GOAL_STATE_CANCELING},
|
std::make_tuple(GOAL_EVENT_CANCEL, GOAL_STATE_CANCELING, true, false),
|
||||||
{GOAL_EVENT_SET_SUCCEEDED, GOAL_STATE_SUCCEEDED},
|
std::make_tuple(GOAL_EVENT_SET_SUCCEEDED, GOAL_STATE_SUCCEEDED, false, false),
|
||||||
},
|
},
|
||||||
{
|
{
|
||||||
{GOAL_EVENT_EXECUTE, GOAL_STATE_EXECUTING},
|
std::make_tuple(GOAL_EVENT_EXECUTE, GOAL_STATE_EXECUTING, true, true),
|
||||||
{GOAL_EVENT_CANCEL, GOAL_STATE_CANCELING},
|
std::make_tuple(GOAL_EVENT_CANCEL, GOAL_STATE_CANCELING, true, false),
|
||||||
{GOAL_EVENT_SET_ABORTED, GOAL_STATE_ABORTED},
|
std::make_tuple(GOAL_EVENT_SET_ABORTED, GOAL_STATE_ABORTED, false, false),
|
||||||
},
|
},
|
||||||
{
|
{
|
||||||
{GOAL_EVENT_EXECUTE, GOAL_STATE_EXECUTING},
|
std::make_tuple(GOAL_EVENT_EXECUTE, GOAL_STATE_EXECUTING, true, true),
|
||||||
{GOAL_EVENT_SET_SUCCEEDED, GOAL_STATE_SUCCEEDED},
|
std::make_tuple(GOAL_EVENT_SET_SUCCEEDED, GOAL_STATE_SUCCEEDED, false, false),
|
||||||
},
|
},
|
||||||
{
|
{
|
||||||
{GOAL_EVENT_EXECUTE, GOAL_STATE_EXECUTING},
|
std::make_tuple(GOAL_EVENT_EXECUTE, GOAL_STATE_EXECUTING, true, true),
|
||||||
{GOAL_EVENT_SET_ABORTED, GOAL_STATE_ABORTED},
|
std::make_tuple(GOAL_EVENT_SET_ABORTED, GOAL_STATE_ABORTED, false, false),
|
||||||
},
|
},
|
||||||
{
|
{
|
||||||
{GOAL_EVENT_CANCEL, GOAL_STATE_CANCELING},
|
std::make_tuple(GOAL_EVENT_CANCEL, GOAL_STATE_CANCELING, true, false),
|
||||||
{GOAL_EVENT_SET_CANCELED, GOAL_STATE_CANCELED},
|
std::make_tuple(GOAL_EVENT_SET_CANCELED, GOAL_STATE_CANCELED, false, false),
|
||||||
},
|
},
|
||||||
{
|
{
|
||||||
{GOAL_EVENT_CANCEL, GOAL_STATE_CANCELING},
|
std::make_tuple(GOAL_EVENT_CANCEL, GOAL_STATE_CANCELING, true, false),
|
||||||
{GOAL_EVENT_SET_ABORTED, GOAL_STATE_ABORTED},
|
std::make_tuple(GOAL_EVENT_SET_ABORTED, GOAL_STATE_ABORTED, false, false),
|
||||||
},
|
},
|
||||||
// This is an odd case, but valid nonetheless
|
// This is an odd case, but valid nonetheless
|
||||||
{
|
{
|
||||||
{GOAL_EVENT_CANCEL, GOAL_STATE_CANCELING},
|
std::make_tuple(GOAL_EVENT_CANCEL, GOAL_STATE_CANCELING, true, false),
|
||||||
{GOAL_EVENT_SET_SUCCEEDED, GOAL_STATE_SUCCEEDED},
|
std::make_tuple(GOAL_EVENT_SET_SUCCEEDED, GOAL_STATE_SUCCEEDED, false, false),
|
||||||
},
|
},
|
||||||
};
|
};
|
||||||
|
|
||||||
|
@ -277,27 +285,27 @@ INSTANTIATE_TEST_CASE_P(
|
||||||
|
|
||||||
const StateTransitionSequence invalid_state_transition_sequences[] = {
|
const StateTransitionSequence invalid_state_transition_sequences[] = {
|
||||||
{
|
{
|
||||||
{GOAL_EVENT_EXECUTE, GOAL_STATE_EXECUTING},
|
std::make_tuple(GOAL_EVENT_EXECUTE, GOAL_STATE_EXECUTING, true, true),
|
||||||
{GOAL_EVENT_CANCEL, GOAL_STATE_CANCELING},
|
std::make_tuple(GOAL_EVENT_CANCEL, GOAL_STATE_CANCELING, true, false),
|
||||||
{GOAL_EVENT_EXECUTE, GOAL_STATE_UNKNOWN},
|
std::make_tuple(GOAL_EVENT_EXECUTE, GOAL_STATE_UNKNOWN, false, false),
|
||||||
},
|
},
|
||||||
{
|
{
|
||||||
{GOAL_EVENT_EXECUTE, GOAL_STATE_EXECUTING},
|
std::make_tuple(GOAL_EVENT_EXECUTE, GOAL_STATE_EXECUTING, true, true),
|
||||||
{GOAL_EVENT_CANCEL, GOAL_STATE_CANCELING},
|
std::make_tuple(GOAL_EVENT_CANCEL, GOAL_STATE_CANCELING, true, false),
|
||||||
{GOAL_EVENT_CANCEL, GOAL_STATE_UNKNOWN},
|
std::make_tuple(GOAL_EVENT_CANCEL, GOAL_STATE_UNKNOWN, false, false),
|
||||||
},
|
},
|
||||||
{
|
{
|
||||||
{GOAL_EVENT_EXECUTE, GOAL_STATE_EXECUTING},
|
std::make_tuple(GOAL_EVENT_EXECUTE, GOAL_STATE_EXECUTING, true, true),
|
||||||
{GOAL_EVENT_EXECUTE, GOAL_STATE_UNKNOWN},
|
std::make_tuple(GOAL_EVENT_EXECUTE, GOAL_STATE_UNKNOWN, false, false),
|
||||||
},
|
},
|
||||||
{
|
{
|
||||||
{GOAL_EVENT_SET_CANCELED, GOAL_STATE_UNKNOWN},
|
std::make_tuple(GOAL_EVENT_SET_CANCELED, GOAL_STATE_UNKNOWN, false, false),
|
||||||
},
|
},
|
||||||
{
|
{
|
||||||
{GOAL_EVENT_SET_SUCCEEDED, GOAL_STATE_UNKNOWN},
|
std::make_tuple(GOAL_EVENT_SET_SUCCEEDED, GOAL_STATE_UNKNOWN, false, false),
|
||||||
},
|
},
|
||||||
{
|
{
|
||||||
{GOAL_EVENT_SET_ABORTED, GOAL_STATE_UNKNOWN},
|
std::make_tuple(GOAL_EVENT_SET_ABORTED, GOAL_STATE_UNKNOWN, false, false),
|
||||||
},
|
},
|
||||||
};
|
};
|
||||||
|
|
||||||
|
|
Loading…
Add table
Add a link
Reference in a new issue