@@ -492,6 +492,7 @@ TEST_F(BTActionNodeTestFixture, test_server_cancel)
492492 // is at least 1000000 x 50 ms
493493 EXPECT_EQ (ticks, 7 );
494494}
495+
495496TEST_F (BTActionNodeTestFixture, test_run_id_initialization_and_persistence)
496497{
497498 // create tree with is_global="true" to enable RunID checking
@@ -503,7 +504,7 @@ TEST_F(BTActionNodeTestFixture, test_run_id_initialization_and_persistence)
503504 </BehaviorTree>
504505 </root>)" ;
505506
506- config_->blackboard ->set <std::chrono::milliseconds>(" server_timeout" , 200ms );
507+ config_->blackboard ->set <std::chrono::milliseconds>(" server_timeout" , 100ms );
507508 config_->blackboard ->set <std::chrono::milliseconds>(" bt_loop_duration" , 10ms);
508509
509510 // Set initial RunID
@@ -535,7 +536,7 @@ TEST_F(BTActionNodeTestFixture, test_run_id_changes_trigger_reinitialization)
535536 </BehaviorTree>
536537 </root>)" ;
537538
538- config_->blackboard ->set <std::chrono::milliseconds>(" server_timeout" , 200ms );
539+ config_->blackboard ->set <std::chrono::milliseconds>(" server_timeout" , 100ms );
539540 config_->blackboard ->set <std::chrono::milliseconds>(" bt_loop_duration" , 10ms);
540541
541542 tree_ = std::make_shared<BT::Tree>(factory_->createTreeFromText (xml_txt, config_->blackboard ));
@@ -565,11 +566,11 @@ TEST_F(BTActionNodeTestFixture, test_run_id_non_global_mode_unaffected)
565566 R"(
566567 <root BTCPP_format="4">
567568 <BehaviorTree ID="MainTree">
568- <Fibonacci order="50 " />
569+ <Fibonacci order="10 " />
569570 </BehaviorTree>
570571 </root>)" ;
571572
572- config_->blackboard ->set <std::chrono::milliseconds>(" server_timeout" , 20ms );
573+ config_->blackboard ->set <std::chrono::milliseconds>(" server_timeout" , 100ms );
573574 config_->blackboard ->set <std::chrono::milliseconds>(" bt_loop_duration" , 10ms);
574575
575576 tree_ = std::make_shared<BT::Tree>(factory_->createTreeFromText (xml_txt, config_->blackboard ));
@@ -581,6 +582,91 @@ TEST_F(BTActionNodeTestFixture, test_run_id_non_global_mode_unaffected)
581582 EXPECT_EQ (result, BT::NodeStatus::RUNNING);
582583}
583584
585+ TEST_F (BTActionNodeTestFixture, test_run_id_missing_from_blackboard)
586+ {
587+ // Test behavior when run_id is not set - should work like old behavior
588+ std::string xml_txt =
589+ R"(
590+ <root BTCPP_format="4">
591+ <BehaviorTree ID="MainTree">
592+ <Fibonacci order="5" is_global="true" />
593+ </BehaviorTree>
594+ </root>)" ;
595+
596+ config_->blackboard ->set <std::chrono::milliseconds>(" server_timeout" , 100ms);
597+ config_->blackboard ->set <std::chrono::milliseconds>(" bt_loop_duration" , 10ms);
598+
599+ // Don't set run_id - test graceful handling
600+ tree_ = std::make_shared<BT::Tree>(factory_->createTreeFromText (xml_txt, config_->blackboard ));
601+ action_server_->setHandleGoalSleepDuration (2ms);
602+ action_server_->setServerLoopRate (10ns);
603+
604+ // Should work like old behavior when RunID is missing
605+ auto result = tree_->tickOnce ();
606+ EXPECT_EQ (result, BT::NodeStatus::RUNNING);
607+
608+ tree_->haltTree ();
609+ }
610+
611+ TEST_F (BTActionNodeTestFixture, test_run_id_change_during_execution)
612+ {
613+ // Test RunID change while node is already running (key preemption scenario)
614+ std::string xml_txt =
615+ R"(
616+ <root BTCPP_format="4">
617+ <BehaviorTree ID="MainTree">
618+ <Fibonacci order="100" is_global="true" />
619+ </BehaviorTree>
620+ </root>)" ;
621+
622+ config_->blackboard ->set <std::chrono::milliseconds>(" server_timeout" , 100ms);
623+ config_->blackboard ->set <std::chrono::milliseconds>(" bt_loop_duration" , 10ms);
624+ config_->blackboard ->set <uint64_t >(" run_id" , 1 );
625+
626+ tree_ = std::make_shared<BT::Tree>(factory_->createTreeFromText (xml_txt, config_->blackboard ));
627+ action_server_->setHandleGoalSleepDuration (2ms);
628+ action_server_->setServerLoopRate (10ns);
629+
630+ // Start execution with run_id = 1
631+ auto result = tree_->tickOnce ();
632+ EXPECT_EQ (result, BT::NodeStatus::RUNNING);
633+
634+ // Change RunID while running (simulates new navigation goal)
635+ config_->blackboard ->set <uint64_t >(" run_id" , 2 );
636+
637+ // Next tick should detect change and reinitialize
638+ result = tree_->tickOnce ();
639+ EXPECT_EQ (result, BT::NodeStatus::RUNNING);
640+
641+ tree_->haltTree ();
642+ }
643+
644+ TEST_F (BTActionNodeTestFixture, test_run_id_zero_edge_case)
645+ {
646+ std::string xml_txt =
647+ R"(
648+ <root BTCPP_format="4">
649+ <BehaviorTree ID="MainTree">
650+ <Fibonacci order="5" is_global="true" />
651+ </BehaviorTree>
652+ </root>)" ;
653+
654+ config_->blackboard ->set <std::chrono::milliseconds>(" server_timeout" , 100ms);
655+ config_->blackboard ->set <std::chrono::milliseconds>(" bt_loop_duration" , 10ms);
656+
657+ // Test with RunID = 0 (edge case)
658+ config_->blackboard ->set <uint64_t >(" run_id" , 0 );
659+
660+ tree_ = std::make_shared<BT::Tree>(factory_->createTreeFromText (xml_txt, config_->blackboard ));
661+ action_server_->setHandleGoalSleepDuration (2ms);
662+ action_server_->setServerLoopRate (10ns);
663+
664+ auto result = tree_->tickOnce ();
665+ EXPECT_EQ (result, BT::NodeStatus::RUNNING);
666+
667+ tree_->haltTree ();
668+ }
669+
584670int main (int argc, char ** argv)
585671{
586672 ::testing::InitGoogleTest (&argc, argv);
0 commit comments