55#include <gtest/gtest.h>
56#include <rclcpp/rclcpp.hpp>
69rclcpp::NodeOptions makeOptionsWithFreshContext(std::shared_ptr<rclcpp::Context>& context_out)
71 context_out = std::make_shared<rclcpp::Context>();
72 context_out->init(0,
nullptr);
78TEST(RegisterNodeResetOnPreShutdownTest, ExplicitShutdownDestroysNode)
80 std::shared_ptr<rclcpp::Context> context;
81 rclcpp::NodeOptions
options = makeOptionsWithFreshContext(context);
83 rclcpp::Node::SharedPtr node = std::make_shared<rclcpp::Node>(
"logger_reset_test", options);
84 std::weak_ptr<rclcpp::Node> weak_node = node;
90 EXPECT_FALSE(weak_node.expired());
97 context->shutdown(
"test shutdown");
99 EXPECT_EQ(node,
nullptr) <<
"the caller's own node slot must be reset by the callback";
100 EXPECT_TRUE(weak_node.expired()) <<
"node must be destroyed before rcl_shutdown(), not after";
113TEST(RegisterNodeResetOnPreShutdownTest, LockedReadAfterResetDoesNotDereferenceNull)
115 std::shared_ptr<rclcpp::Context> context;
116 rclcpp::NodeOptions
options = makeOptionsWithFreshContext(context);
118 rclcpp::Node::SharedPtr node = std::make_shared<rclcpp::Node>(
"race_test_node", options);
122 context->shutdown(
"simulate a shutdown racing ahead of the first read");
123 ASSERT_EQ(node,
nullptr);
125 std::lock_guard<std::mutex> lock(*mutex);
126 EXPECT_FALSE(
static_cast<bool>(node)) <<
"node must be safely observed as reset while holding the lock";
142TEST(RegisterNodeResetOnPreShutdownTest, DoesNotRetainNodeOrGuardWithoutExplicitShutdown)
144 std::shared_ptr<rclcpp::Context> context;
145 rclcpp::NodeOptions
options = makeOptionsWithFreshContext(context);
147 std::weak_ptr<rclcpp::Node> weak_node;
148 std::weak_ptr<std::mutex> weak_mutex;
150 rclcpp::Node::SharedPtr node = std::make_shared<rclcpp::Node>(
"cycle_test_node", options);
154 EXPECT_FALSE(weak_node.expired());
155 EXPECT_FALSE(weak_mutex.expired());
161 EXPECT_TRUE(weak_mutex.expired()) <<
"mutex must not be kept alive by the callback's capture of it";
162 EXPECT_TRUE(weak_node.expired()) <<
"node must not be kept alive by the callback's capture of it";
166 context->shutdown(
"test cleanup");
175TEST(SetNodeLoggerNameTest, SafeAcrossExplicitShutdown)
177 rclcpp::init(0,
nullptr);
181 ASSERT_NE(logger_before_shutdown.get_name(),
nullptr);
182 const std::string name_before_shutdown = logger_before_shutdown.get_name();
185 RCLCPP_INFO(logger_before_shutdown,
"before shutdown");
187 catch (
const std::exception& ex)
189 FAIL() <<
"logging before shutdown must not throw: " << ex.what();
201 ASSERT_NE(logger_after_shutdown.get_name(),
nullptr);
202 EXPECT_STREQ(logger_after_shutdown.get_name(), name_before_shutdown.c_str());
214 ASSERT_NE(logger_after_second_call.get_name(),
nullptr);
215 EXPECT_STREQ(logger_after_second_call.get_name(), name_before_shutdown.c_str())
216 <<
"setNodeLoggerName() must not change the logger after its node has already been reset";
217 RCLCPP_INFO(logger_after_second_call,
"after shutdown");
219 catch (
const std::exception& ex)
221 FAIL() <<
"setNodeLoggerName()/logging after shutdown must not throw: " << ex.what();
229 testing::InitGoogleTest(&argc, argv);
230 return RUN_ALL_TESTS();
std::shared_ptr< std::mutex > registerNodeResetOnPreShutdown(rclcpp::Node::SharedPtr &node)
rclcpp::Logger getLogger(const std::string &name)
Creates a namespaced logger.
void setNodeLoggerName(const std::string &name)
Call once after creating a node to initialize logging namespaces.
TEST(AllValid, Instantiate)
int main(int argc, char **argv)