Skip to content

Commit 97c386c

Browse files
authored
LifecycleNode bugfix and add test cases (#2562)
* LifecycleNode base class resource needs to be reset via dtor. Signed-off-by: Tomoya Fujita <[email protected]> * add debug notice that prints LifecycleNode is not shutdown in dtor. Currently it is user application responsibility to manage the all state control. See more details for #2520. Signed-off-by: Tomoya Fujita <[email protected]> * add test cases to call shutdown from each primary state. Signed-off-by: Tomoya Fujita <[email protected]> * address review comments. Signed-off-by: Tomoya Fujita <[email protected]> --------- Signed-off-by: Tomoya Fujita <[email protected]>
1 parent 1a3dfaf commit 97c386c

File tree

2 files changed

+77
-0
lines changed

2 files changed

+77
-0
lines changed

rclcpp_lifecycle/src/lifecycle_node.cpp

+12
Original file line numberDiff line numberDiff line change
@@ -152,8 +152,19 @@ LifecycleNode::LifecycleNode(
152152

153153
LifecycleNode::~LifecycleNode()
154154
{
155+
auto current_state = LifecycleNode::get_current_state().id();
156+
if (current_state != lifecycle_msgs::msg::State::PRIMARY_STATE_FINALIZED) {
157+
// This might be leaving sensors and devices without shutting down unintentionally.
158+
// It is user's responsibility to call shutdown to avoid leaving them unknow states.
159+
RCLCPP_WARN(
160+
rclcpp::get_logger("rclcpp_lifecycle"),
161+
"LifecycleNode is not shut down: Node still in state(%u) in destructor",
162+
current_state);
163+
}
164+
155165
// release sub-interfaces in an order that allows them to consult with node_base during tear-down
156166
node_waitables_.reset();
167+
node_type_descriptions_.reset();
157168
node_time_source_.reset();
158169
node_parameters_.reset();
159170
node_clock_.reset();
@@ -162,6 +173,7 @@ LifecycleNode::~LifecycleNode()
162173
node_timers_.reset();
163174
node_logging_.reset();
164175
node_graph_.reset();
176+
node_base_.reset();
165177
}
166178

167179
const char *

rclcpp_lifecycle/test/test_lifecycle_node.cpp

+65
Original file line numberDiff line numberDiff line change
@@ -431,6 +431,71 @@ TEST_F(TestDefaultStateMachine, bad_mood) {
431431
EXPECT_EQ(1u, test_node->number_of_callbacks);
432432
}
433433

434+
TEST_F(TestDefaultStateMachine, shutdown_from_each_primary_state) {
435+
auto success = rclcpp_lifecycle::node_interfaces::LifecycleNodeInterface::CallbackReturn::SUCCESS;
436+
auto reset_key = rclcpp_lifecycle::node_interfaces::LifecycleNodeInterface::CallbackReturn::ERROR;
437+
438+
// PRIMARY_STATE_UNCONFIGURED to shutdown
439+
{
440+
auto ret = reset_key;
441+
auto test_node = std::make_shared<EmptyLifecycleNode>("testnode");
442+
auto finalized = test_node->shutdown(ret);
443+
EXPECT_EQ(success, ret);
444+
EXPECT_EQ(finalized.id(), State::PRIMARY_STATE_FINALIZED);
445+
}
446+
447+
// PRIMARY_STATE_INACTIVE to shutdown
448+
{
449+
auto ret = reset_key;
450+
auto test_node = std::make_shared<EmptyLifecycleNode>("testnode");
451+
auto configured = test_node->configure(ret);
452+
EXPECT_EQ(success, ret);
453+
EXPECT_EQ(configured.id(), State::PRIMARY_STATE_INACTIVE);
454+
ret = reset_key;
455+
auto finalized = test_node->shutdown(ret);
456+
EXPECT_EQ(success, ret);
457+
EXPECT_EQ(finalized.id(), State::PRIMARY_STATE_FINALIZED);
458+
}
459+
460+
// PRIMARY_STATE_ACTIVE to shutdown
461+
{
462+
auto ret = reset_key;
463+
auto test_node = std::make_shared<EmptyLifecycleNode>("testnode");
464+
auto configured = test_node->configure(ret);
465+
EXPECT_EQ(success, ret);
466+
EXPECT_EQ(configured.id(), State::PRIMARY_STATE_INACTIVE);
467+
ret = reset_key;
468+
auto activated = test_node->activate(ret);
469+
EXPECT_EQ(success, ret);
470+
EXPECT_EQ(activated.id(), State::PRIMARY_STATE_ACTIVE);
471+
ret = reset_key;
472+
auto finalized = test_node->shutdown(ret);
473+
EXPECT_EQ(success, ret);
474+
EXPECT_EQ(finalized.id(), State::PRIMARY_STATE_FINALIZED);
475+
}
476+
477+
// PRIMARY_STATE_FINALIZED to shutdown
478+
{
479+
auto ret = reset_key;
480+
auto test_node = std::make_shared<EmptyLifecycleNode>("testnode");
481+
auto configured = test_node->configure(ret);
482+
EXPECT_EQ(success, ret);
483+
EXPECT_EQ(configured.id(), State::PRIMARY_STATE_INACTIVE);
484+
ret = reset_key;
485+
auto activated = test_node->activate(ret);
486+
EXPECT_EQ(success, ret);
487+
EXPECT_EQ(activated.id(), State::PRIMARY_STATE_ACTIVE);
488+
ret = reset_key;
489+
auto finalized = test_node->shutdown(ret);
490+
EXPECT_EQ(success, ret);
491+
EXPECT_EQ(finalized.id(), State::PRIMARY_STATE_FINALIZED);
492+
ret = reset_key;
493+
auto finalized_again = test_node->shutdown(ret);
494+
EXPECT_EQ(reset_key, ret);
495+
EXPECT_EQ(finalized_again.id(), State::PRIMARY_STATE_FINALIZED);
496+
}
497+
}
498+
434499
TEST_F(TestDefaultStateMachine, lifecycle_subscriber) {
435500
auto test_node = std::make_shared<MoodyLifecycleNode<GoodMood>>("testnode");
436501

0 commit comments

Comments
 (0)