@@ -2169,3 +2169,102 @@ TEST_F(
21692169 EXPECT_EQ (controller_interface::return_type::ERROR , switch_future.get ());
21702170 }
21712171}
2172+
2173+ class TestControllerManagerChainableControllerFailedActivation
2174+ : public ControllerManagerFixture<controller_manager::ControllerManager>
2175+ {
2176+ };
2177+
2178+ TEST_F (
2179+ TestControllerManagerChainableControllerFailedActivation,
2180+ test_chainable_controllers_failed_activation_and_then_reconfiguring_it)
2181+ {
2182+ const std::string test_controller_name = " test_chainable_controller_2" ;
2183+
2184+ const auto strictness = controller_manager_msgs::srv::SwitchController::Request::STRICT ;
2185+ controller_interface::InterfaceConfiguration cmd_itfs_cfg;
2186+ controller_interface::InterfaceConfiguration itfs_cfg;
2187+ cmd_itfs_cfg.type = controller_interface::interface_configuration_type::INDIVIDUAL ;
2188+ itfs_cfg.type = controller_interface::interface_configuration_type::INDIVIDUAL ;
2189+
2190+ // controller 4
2191+ auto test_chainable_controller =
2192+ std::make_shared<test_chainable_controller::TestChainableController>();
2193+ cmd_itfs_cfg.names = {" joint1/position" };
2194+ itfs_cfg.names = {" joint2/velocity" };
2195+ test_chainable_controller->set_command_interface_configuration (cmd_itfs_cfg);
2196+ test_chainable_controller->set_state_interface_configuration (itfs_cfg);
2197+ test_chainable_controller->set_reference_interface_names ({" modified_joint1/position" });
2198+ test_chainable_controller->set_exported_state_interface_names ({" modified_joint2/velocity" });
2199+ test_chainable_controller->fail_on_activate = true ;
2200+
2201+ cm_->add_controller (
2202+ test_chainable_controller, test_chainable_controller::TEST_CONTROLLER_NAME ,
2203+ test_chainable_controller::TEST_CONTROLLER_CLASS_NAME );
2204+
2205+ EXPECT_EQ (1u , cm_->get_loaded_controllers ().size ());
2206+ EXPECT_EQ (2 , test_chainable_controller.use_count ());
2207+ EXPECT_EQ (
2208+ controller_interface::return_type::OK ,
2209+ cm_->update (time_, rclcpp::Duration::from_seconds (0.01 )));
2210+
2211+ EXPECT_EQ (
2212+ lifecycle_msgs::msg::State::PRIMARY_STATE_UNCONFIGURED ,
2213+ test_chainable_controller->get_lifecycle_state ().id ());
2214+
2215+ // configure controllers
2216+ {
2217+ ControllerManagerRunner cm_runner (this );
2218+ EXPECT_EQ (
2219+ controller_interface::return_type::OK ,
2220+ cm_->configure_controller (test_chainable_controller::TEST_CONTROLLER_NAME ));
2221+ }
2222+
2223+ EXPECT_EQ (
2224+ lifecycle_msgs::msg::State::PRIMARY_STATE_INACTIVE ,
2225+ test_chainable_controller->get_lifecycle_state ().id ());
2226+
2227+ std::vector<std::string> start_controllers = {test_chainable_controller::TEST_CONTROLLER_NAME };
2228+ std::vector<std::string> stop_controllers = {};
2229+ {
2230+ auto switch_future = std::async (
2231+ std::launch::async, &controller_manager::ControllerManager::switch_controller, cm_,
2232+ start_controllers, stop_controllers, strictness, true , rclcpp::Duration (0 , 0 ));
2233+
2234+ ASSERT_EQ (std::future_status::timeout, switch_future.wait_for (std::chrono::milliseconds (100 )))
2235+ << " switch_controller should be blocking until next update cycle" ;
2236+ EXPECT_EQ (
2237+ controller_interface::return_type::OK ,
2238+ cm_->update (time_, rclcpp::Duration::from_seconds (0.01 )));
2239+ {
2240+ ControllerManagerRunner cm_runner (this );
2241+ EXPECT_EQ (controller_interface::return_type::ERROR , switch_future.get ());
2242+ }
2243+ }
2244+
2245+ EXPECT_EQ (
2246+ lifecycle_msgs::msg::State::PRIMARY_STATE_UNCONFIGURED ,
2247+ test_chainable_controller->get_lifecycle_state ().id ());
2248+ // Now, after reconfiguring it, it should work
2249+ test_chainable_controller->fail_on_activate = false ;
2250+
2251+ {
2252+ ControllerManagerRunner cm_runner (this );
2253+ EXPECT_EQ (
2254+ controller_interface::return_type::OK ,
2255+ cm_->configure_controller (test_chainable_controller::TEST_CONTROLLER_NAME ));
2256+ EXPECT_EQ (
2257+ lifecycle_msgs::msg::State::PRIMARY_STATE_INACTIVE ,
2258+ test_chainable_controller->get_lifecycle_state ().id ());
2259+
2260+ auto switch_future = std::async (
2261+ std::launch::async, &controller_manager::ControllerManager::switch_controller, cm_,
2262+ start_controllers, stop_controllers, strictness, true , rclcpp::Duration (0 , 0 ));
2263+ ASSERT_EQ (std::future_status::ready, switch_future.wait_for (std::chrono::milliseconds (100 )))
2264+ << " switch_controller should be blocking until next update cycle" ;
2265+ EXPECT_EQ (controller_interface::return_type::OK , switch_future.get ());
2266+ EXPECT_EQ (
2267+ lifecycle_msgs::msg::State::PRIMARY_STATE_ACTIVE ,
2268+ test_chainable_controller->get_lifecycle_state ().id ());
2269+ }
2270+ }
0 commit comments