@@ -488,6 +488,7 @@ TEST_F(BTActionNodeTestFixture, test_server_cancel)
488488 // is at least 1000000 x 50 ms
489489 EXPECT_EQ (ticks, 7 );
490490}
491+
491492TEST_F (BTActionNodeTestFixture, test_run_id_initialization_and_persistence)
492493{
493494 // create tree with is_global="true" to enable RunID checking
@@ -499,7 +500,7 @@ TEST_F(BTActionNodeTestFixture, test_run_id_initialization_and_persistence)
499500 </BehaviorTree>
500501 </root>)" ;
501502
502- config_->blackboard ->set <std::chrono::milliseconds>(" server_timeout" , 200ms );
503+ config_->blackboard ->set <std::chrono::milliseconds>(" server_timeout" , 100ms );
503504 config_->blackboard ->set <std::chrono::milliseconds>(" bt_loop_duration" , 10ms);
504505
505506 // Set initial RunID
@@ -531,7 +532,7 @@ TEST_F(BTActionNodeTestFixture, test_run_id_changes_trigger_reinitialization)
531532 </BehaviorTree>
532533 </root>)" ;
533534
534- config_->blackboard ->set <std::chrono::milliseconds>(" server_timeout" , 200ms );
535+ config_->blackboard ->set <std::chrono::milliseconds>(" server_timeout" , 100ms );
535536 config_->blackboard ->set <std::chrono::milliseconds>(" bt_loop_duration" , 10ms);
536537
537538 tree_ = std::make_shared<BT::Tree>(factory_->createTreeFromText (xml_txt, config_->blackboard ));
@@ -561,11 +562,11 @@ TEST_F(BTActionNodeTestFixture, test_run_id_non_global_mode_unaffected)
561562 R"(
562563 <root BTCPP_format="4">
563564 <BehaviorTree ID="MainTree">
564- <Fibonacci order="50 " />
565+ <Fibonacci order="10 " />
565566 </BehaviorTree>
566567 </root>)" ;
567568
568- config_->blackboard ->set <std::chrono::milliseconds>(" server_timeout" , 20ms );
569+ config_->blackboard ->set <std::chrono::milliseconds>(" server_timeout" , 100ms );
569570 config_->blackboard ->set <std::chrono::milliseconds>(" bt_loop_duration" , 10ms);
570571
571572 tree_ = std::make_shared<BT::Tree>(factory_->createTreeFromText (xml_txt, config_->blackboard ));
@@ -577,6 +578,91 @@ TEST_F(BTActionNodeTestFixture, test_run_id_non_global_mode_unaffected)
577578 EXPECT_EQ (result, BT::NodeStatus::RUNNING);
578579}
579580
581+ TEST_F (BTActionNodeTestFixture, test_run_id_missing_from_blackboard)
582+ {
583+ // Test behavior when run_id is not set - should work like old behavior
584+ std::string xml_txt =
585+ R"(
586+ <root BTCPP_format="4">
587+ <BehaviorTree ID="MainTree">
588+ <Fibonacci order="5" is_global="true" />
589+ </BehaviorTree>
590+ </root>)" ;
591+
592+ config_->blackboard ->set <std::chrono::milliseconds>(" server_timeout" , 100ms);
593+ config_->blackboard ->set <std::chrono::milliseconds>(" bt_loop_duration" , 10ms);
594+
595+ // Don't set run_id - test graceful handling
596+ tree_ = std::make_shared<BT::Tree>(factory_->createTreeFromText (xml_txt, config_->blackboard ));
597+ action_server_->setHandleGoalSleepDuration (2ms);
598+ action_server_->setServerLoopRate (10ns);
599+
600+ // Should work like old behavior when RunID is missing
601+ auto result = tree_->tickOnce ();
602+ EXPECT_EQ (result, BT::NodeStatus::RUNNING);
603+
604+ tree_->haltTree ();
605+ }
606+
607+ TEST_F (BTActionNodeTestFixture, test_run_id_change_during_execution)
608+ {
609+ // Test RunID change while node is already running (key preemption scenario)
610+ std::string xml_txt =
611+ R"(
612+ <root BTCPP_format="4">
613+ <BehaviorTree ID="MainTree">
614+ <Fibonacci order="100" is_global="true" />
615+ </BehaviorTree>
616+ </root>)" ;
617+
618+ config_->blackboard ->set <std::chrono::milliseconds>(" server_timeout" , 100ms);
619+ config_->blackboard ->set <std::chrono::milliseconds>(" bt_loop_duration" , 10ms);
620+ config_->blackboard ->set <uint64_t >(" run_id" , 1 );
621+
622+ tree_ = std::make_shared<BT::Tree>(factory_->createTreeFromText (xml_txt, config_->blackboard ));
623+ action_server_->setHandleGoalSleepDuration (2ms);
624+ action_server_->setServerLoopRate (10ns);
625+
626+ // Start execution with run_id = 1
627+ auto result = tree_->tickOnce ();
628+ EXPECT_EQ (result, BT::NodeStatus::RUNNING);
629+
630+ // Change RunID while running (simulates new navigation goal)
631+ config_->blackboard ->set <uint64_t >(" run_id" , 2 );
632+
633+ // Next tick should detect change and reinitialize
634+ result = tree_->tickOnce ();
635+ EXPECT_EQ (result, BT::NodeStatus::RUNNING);
636+
637+ tree_->haltTree ();
638+ }
639+
640+ TEST_F (BTActionNodeTestFixture, test_run_id_zero_edge_case)
641+ {
642+ std::string xml_txt =
643+ R"(
644+ <root BTCPP_format="4">
645+ <BehaviorTree ID="MainTree">
646+ <Fibonacci order="5" is_global="true" />
647+ </BehaviorTree>
648+ </root>)" ;
649+
650+ config_->blackboard ->set <std::chrono::milliseconds>(" server_timeout" , 100ms);
651+ config_->blackboard ->set <std::chrono::milliseconds>(" bt_loop_duration" , 10ms);
652+
653+ // Test with RunID = 0 (edge case)
654+ config_->blackboard ->set <uint64_t >(" run_id" , 0 );
655+
656+ tree_ = std::make_shared<BT::Tree>(factory_->createTreeFromText (xml_txt, config_->blackboard ));
657+ action_server_->setHandleGoalSleepDuration (2ms);
658+ action_server_->setServerLoopRate (10ns);
659+
660+ auto result = tree_->tickOnce ();
661+ EXPECT_EQ (result, BT::NodeStatus::RUNNING);
662+
663+ tree_->haltTree ();
664+ }
665+
580666int main (int argc, char ** argv)
581667{
582668 ::testing::InitGoogleTest (&argc, argv);
0 commit comments