@@ -3037,3 +3037,264 @@ TEST_F(
30373037 test_controller->get_lifecycle_state ().id ());
30383038 }
30393039}
3040+
3041+ class TestControllerManagerWithHandlingExceptions
3042+ : public ControllerManagerFixture<controller_manager::ControllerManager>
3043+ {
3044+ };
3045+
3046+ TEST_F (TestControllerManagerWithHandlingExceptions, controller_lifecycle_on_exceptions)
3047+ {
3048+ auto test_controller = std::make_shared<test_controller::TestController>();
3049+
3050+ test_controller->throw_on_initialize = true ;
3051+
3052+ EXPECT_NO_THROW (cm_->add_controller (
3053+ test_controller, test_controller::TEST_CONTROLLER_NAME,
3054+ test_controller::TEST_CONTROLLER_CLASS_NAME));
3055+ EXPECT_EQ (0u , cm_->get_loaded_controllers ().size ());
3056+
3057+ test_controller->throw_on_initialize = false ;
3058+ cm_->add_controller (
3059+ test_controller, test_controller::TEST_CONTROLLER_NAME,
3060+ test_controller::TEST_CONTROLLER_CLASS_NAME);
3061+ EXPECT_EQ (1u , cm_->get_loaded_controllers ().size ());
3062+ EXPECT_EQ (2 , test_controller.use_count ());
3063+
3064+ // setup interface to claim from controllers
3065+ controller_interface::InterfaceConfiguration cmd_itfs_cfg;
3066+ cmd_itfs_cfg.type = controller_interface::interface_configuration_type::INDIVIDUAL;
3067+ for (const auto & interface : ros2_control_test_assets::TEST_ACTUATOR_HARDWARE_COMMAND_INTERFACES)
3068+ {
3069+ cmd_itfs_cfg.names .push_back (interface);
3070+ }
3071+ test_controller->set_command_interface_configuration (cmd_itfs_cfg);
3072+
3073+ controller_interface::InterfaceConfiguration state_itfs_cfg;
3074+ state_itfs_cfg.type = controller_interface::interface_configuration_type::INDIVIDUAL;
3075+ for (const auto & interface : ros2_control_test_assets::TEST_ACTUATOR_HARDWARE_STATE_INTERFACES)
3076+ {
3077+ state_itfs_cfg.names .push_back (interface);
3078+ }
3079+ for (const auto & interface : ros2_control_test_assets::TEST_SENSOR_HARDWARE_STATE_INTERFACES)
3080+ {
3081+ state_itfs_cfg.names .push_back (interface);
3082+ }
3083+ test_controller->set_state_interface_configuration (state_itfs_cfg);
3084+
3085+ EXPECT_EQ (
3086+ controller_interface::return_type::OK,
3087+ cm_->update (time_, rclcpp::Duration::from_seconds (0.01 )));
3088+ EXPECT_EQ (0u , test_controller->internal_counter )
3089+ << " Update should not reach an unconfigured controller" ;
3090+
3091+ EXPECT_EQ (
3092+ lifecycle_msgs::msg::State::PRIMARY_STATE_UNCONFIGURED,
3093+ test_controller->get_lifecycle_state ().id ());
3094+
3095+ // configure controller
3096+ {
3097+ ControllerManagerRunner cm_runner (this );
3098+ EXPECT_EQ (
3099+ controller_interface::return_type::OK,
3100+ cm_->configure_controller (test_controller::TEST_CONTROLLER_NAME));
3101+ }
3102+
3103+ EXPECT_EQ (
3104+ lifecycle_msgs::msg::State::PRIMARY_STATE_INACTIVE,
3105+ test_controller->get_lifecycle_state ().id ());
3106+
3107+ std::vector<std::string> start_controllers = {test_controller::TEST_CONTROLLER_NAME};
3108+ std::vector<std::string> stop_controllers = {};
3109+ {
3110+ ControllerManagerRunner cm_runner (this );
3111+ auto switch_future = std::async (
3112+ std::launch::async, &controller_manager::ControllerManager::switch_controller, cm_,
3113+ start_controllers, stop_controllers,
3114+ controller_manager_msgs::srv::SwitchController::Request::STRICT, true ,
3115+ rclcpp::Duration (0 , 0 ));
3116+ ASSERT_EQ (std::future_status::ready, switch_future.wait_for (std::chrono::milliseconds (100 )))
3117+ << " switch_controller should be blocking until next update cycle" ;
3118+
3119+ EXPECT_EQ (controller_interface::return_type::OK, switch_future.get ());
3120+ }
3121+ EXPECT_EQ (
3122+ controller_interface::return_type::OK,
3123+ cm_->update (time_, rclcpp::Duration::from_seconds (0.01 )));
3124+
3125+ EXPECT_EQ (
3126+ lifecycle_msgs::msg::State::PRIMARY_STATE_ACTIVE, test_controller->get_lifecycle_state ().id ());
3127+
3128+ test_controller->throw_on_update = true ;
3129+ EXPECT_NO_THROW (cm_->update (time_, rclcpp::Duration::from_seconds (0.01 )));
3130+
3131+ EXPECT_EQ (
3132+ lifecycle_msgs::msg::State::PRIMARY_STATE_INACTIVE,
3133+ test_controller->get_lifecycle_state ().id ());
3134+
3135+ test_controller->throw_on_update = false ;
3136+ {
3137+ ControllerManagerRunner cm_runner (this );
3138+ auto switch_future = std::async (
3139+ std::launch::async, &controller_manager::ControllerManager::switch_controller, cm_,
3140+ start_controllers, stop_controllers,
3141+ controller_manager_msgs::srv::SwitchController::Request::STRICT, true ,
3142+ rclcpp::Duration (0 , 0 ));
3143+ ASSERT_EQ (std::future_status::ready, switch_future.wait_for (std::chrono::milliseconds (100 )))
3144+ << " switch_controller should be blocking until next update cycle" ;
3145+
3146+ EXPECT_EQ (controller_interface::return_type::OK, switch_future.get ());
3147+ }
3148+ EXPECT_EQ (
3149+ controller_interface::return_type::OK,
3150+ cm_->update (time_, rclcpp::Duration::from_seconds (0.01 )));
3151+
3152+ EXPECT_EQ (
3153+ lifecycle_msgs::msg::State::PRIMARY_STATE_ACTIVE, test_controller->get_lifecycle_state ().id ());
3154+
3155+ EXPECT_EQ (
3156+ controller_interface::return_type::OK,
3157+ cm_->update (time_, rclcpp::Duration::from_seconds (0.01 )));
3158+
3159+ {
3160+ ControllerManagerRunner cm_runner (this );
3161+ auto switch_future = std::async (
3162+ std::launch::async, &controller_manager::ControllerManager::switch_controller, cm_,
3163+ stop_controllers, start_controllers,
3164+ controller_manager_msgs::srv::SwitchController::Request::STRICT, true ,
3165+ rclcpp::Duration (0 , 0 ));
3166+ ASSERT_EQ (std::future_status::ready, switch_future.wait_for (std::chrono::milliseconds (100 )))
3167+ << " switch_controller should be blocking until next update cycle" ;
3168+
3169+ EXPECT_EQ (controller_interface::return_type::OK, switch_future.get ());
3170+ }
3171+
3172+ EXPECT_EQ (
3173+ lifecycle_msgs::msg::State::PRIMARY_STATE_INACTIVE,
3174+ test_controller->get_lifecycle_state ().id ());
3175+ }
3176+
3177+ class TestControllerManagerNotHandlingExceptions
3178+ : public ControllerManagerFixture<controller_manager::ControllerManager>
3179+ {
3180+ public:
3181+ TestControllerManagerNotHandlingExceptions ()
3182+ : ControllerManagerFixture<controller_manager::ControllerManager>(
3183+ ros2_control_test_assets::minimal_robot_urdf, " " ,
3184+ {rclcpp::Parameter (" handle_exceptions" , false )})
3185+ {
3186+ }
3187+ };
3188+
3189+ TEST_F (TestControllerManagerNotHandlingExceptions, controller_lifecycle_on_exceptions)
3190+ {
3191+ auto test_controller = std::make_shared<test_controller::TestController>();
3192+
3193+ test_controller->throw_on_initialize = true ;
3194+
3195+ EXPECT_THROW (
3196+ cm_->add_controller (
3197+ test_controller, test_controller::TEST_CONTROLLER_NAME,
3198+ test_controller::TEST_CONTROLLER_CLASS_NAME),
3199+ std::runtime_error);
3200+ EXPECT_EQ (0u , cm_->get_loaded_controllers ().size ());
3201+
3202+ test_controller->throw_on_initialize = false ;
3203+ cm_->add_controller (
3204+ test_controller, test_controller::TEST_CONTROLLER_NAME,
3205+ test_controller::TEST_CONTROLLER_CLASS_NAME);
3206+ EXPECT_EQ (1u , cm_->get_loaded_controllers ().size ());
3207+ EXPECT_EQ (2 , test_controller.use_count ());
3208+
3209+ // setup interface to claim from controllers
3210+ controller_interface::InterfaceConfiguration cmd_itfs_cfg;
3211+ cmd_itfs_cfg.type = controller_interface::interface_configuration_type::INDIVIDUAL;
3212+ for (const auto & interface : ros2_control_test_assets::TEST_ACTUATOR_HARDWARE_COMMAND_INTERFACES)
3213+ {
3214+ cmd_itfs_cfg.names .push_back (interface);
3215+ }
3216+ test_controller->set_command_interface_configuration (cmd_itfs_cfg);
3217+
3218+ controller_interface::InterfaceConfiguration state_itfs_cfg;
3219+ state_itfs_cfg.type = controller_interface::interface_configuration_type::INDIVIDUAL;
3220+ for (const auto & interface : ros2_control_test_assets::TEST_ACTUATOR_HARDWARE_STATE_INTERFACES)
3221+ {
3222+ state_itfs_cfg.names .push_back (interface);
3223+ }
3224+ for (const auto & interface : ros2_control_test_assets::TEST_SENSOR_HARDWARE_STATE_INTERFACES)
3225+ {
3226+ state_itfs_cfg.names .push_back (interface);
3227+ }
3228+ test_controller->set_state_interface_configuration (state_itfs_cfg);
3229+
3230+ EXPECT_EQ (
3231+ controller_interface::return_type::OK,
3232+ cm_->update (time_, rclcpp::Duration::from_seconds (0.01 )));
3233+ EXPECT_EQ (0u , test_controller->internal_counter )
3234+ << " Update should not reach an unconfigured controller" ;
3235+
3236+ EXPECT_EQ (
3237+ lifecycle_msgs::msg::State::PRIMARY_STATE_UNCONFIGURED,
3238+ test_controller->get_lifecycle_state ().id ());
3239+
3240+ // configure controller
3241+ {
3242+ ControllerManagerRunner cm_runner (this );
3243+ EXPECT_EQ (
3244+ controller_interface::return_type::OK,
3245+ cm_->configure_controller (test_controller::TEST_CONTROLLER_NAME));
3246+ }
3247+
3248+ EXPECT_EQ (
3249+ lifecycle_msgs::msg::State::PRIMARY_STATE_INACTIVE,
3250+ test_controller->get_lifecycle_state ().id ());
3251+
3252+ std::vector<std::string> start_controllers = {test_controller::TEST_CONTROLLER_NAME};
3253+ std::vector<std::string> stop_controllers = {};
3254+ {
3255+ ControllerManagerRunner cm_runner (this );
3256+ auto switch_future = std::async (
3257+ std::launch::async, &controller_manager::ControllerManager::switch_controller, cm_,
3258+ start_controllers, stop_controllers,
3259+ controller_manager_msgs::srv::SwitchController::Request::STRICT, true ,
3260+ rclcpp::Duration (0 , 0 ));
3261+ ASSERT_EQ (std::future_status::ready, switch_future.wait_for (std::chrono::milliseconds (100 )))
3262+ << " switch_controller should be blocking until next update cycle" ;
3263+
3264+ EXPECT_EQ (controller_interface::return_type::OK, switch_future.get ());
3265+ }
3266+ EXPECT_EQ (
3267+ controller_interface::return_type::OK,
3268+ cm_->update (time_, rclcpp::Duration::from_seconds (0.01 )));
3269+
3270+ EXPECT_EQ (
3271+ lifecycle_msgs::msg::State::PRIMARY_STATE_ACTIVE, test_controller->get_lifecycle_state ().id ());
3272+
3273+ test_controller->throw_on_update = true ;
3274+ EXPECT_THROW (cm_->update (time_, rclcpp::Duration::from_seconds (0.01 )), std::runtime_error);
3275+
3276+ test_controller->throw_on_update = false ;
3277+ EXPECT_EQ (
3278+ controller_interface::return_type::OK,
3279+ cm_->update (time_, rclcpp::Duration::from_seconds (0.01 )));
3280+
3281+ EXPECT_EQ (
3282+ lifecycle_msgs::msg::State::PRIMARY_STATE_ACTIVE, test_controller->get_lifecycle_state ().id ());
3283+
3284+ {
3285+ ControllerManagerRunner cm_runner (this );
3286+ auto switch_future = std::async (
3287+ std::launch::async, &controller_manager::ControllerManager::switch_controller, cm_,
3288+ stop_controllers, start_controllers,
3289+ controller_manager_msgs::srv::SwitchController::Request::STRICT, true ,
3290+ rclcpp::Duration (0 , 0 ));
3291+ ASSERT_EQ (std::future_status::ready, switch_future.wait_for (std::chrono::milliseconds (100 )))
3292+ << " switch_controller should be blocking until next update cycle" ;
3293+
3294+ EXPECT_EQ (controller_interface::return_type::OK, switch_future.get ());
3295+ }
3296+
3297+ EXPECT_EQ (
3298+ lifecycle_msgs::msg::State::PRIMARY_STATE_INACTIVE,
3299+ test_controller->get_lifecycle_state ().id ());
3300+ }
0 commit comments