22
22
#include " controller_manager/controller_manager.hpp"
23
23
#include " controller_manager_test_common.hpp"
24
24
#include " lifecycle_msgs/msg/state.hpp"
25
+ #include " test_controller_failed_activate/test_controller_failed_activate.hpp"
25
26
#include " test_controller_with_interfaces/test_controller_with_interfaces.hpp"
26
27
27
28
using ::testing::_;
@@ -31,6 +32,19 @@ class TestReleaseInterfaces : public ControllerManagerFixture<controller_manager
31
32
{
32
33
};
33
34
35
+ class TestReleaseExclusiveInterfaces
36
+ : public ControllerManagerFixture<controller_manager::ControllerManager>
37
+ {
38
+ public:
39
+ TestReleaseExclusiveInterfaces ()
40
+ : ControllerManagerFixture<controller_manager::ControllerManager>(
41
+ std::string (ros2_control_test_assets::urdf_head) +
42
+ std::string (ros2_control_test_assets::hardware_resources_with_exclusive_interface) +
43
+ std::string (ros2_control_test_assets::urdf_tail))
44
+ {
45
+ }
46
+ };
47
+
34
48
TEST_F (TestReleaseInterfaces, switch_controllers_same_interface)
35
49
{
36
50
std::string controller_type =
@@ -199,3 +213,69 @@ TEST_F(TestReleaseInterfaces, switch_controllers_same_interface)
199
213
abstract_test_controller2.c ->get_state ().id ());
200
214
}
201
215
}
216
+
217
+ TEST_F (TestReleaseExclusiveInterfaces, test_exclusive_interface_switching_failure)
218
+ {
219
+ std::string controller_type =
220
+ test_controller_failed_activate::TEST_CONTROLLER_WITH_INTERFACES_CLASS_NAME;
221
+
222
+ // Load two controllers of different names
223
+ std::string controller_name1 = " test_controller1" ;
224
+ std::string controller_name2 = " test_controller2" ;
225
+ ASSERT_NO_THROW (cm_->load_controller (controller_name1, controller_type));
226
+ ASSERT_NO_THROW (cm_->load_controller (
227
+ controller_name2, test_controller_with_interfaces::TEST_CONTROLLER_WITH_INTERFACES_CLASS_NAME));
228
+ ASSERT_EQ (2u , cm_->get_loaded_controllers ().size ());
229
+ controller_manager::ControllerSpec abstract_test_controller1 = cm_->get_loaded_controllers ()[0 ];
230
+ controller_manager::ControllerSpec abstract_test_controller2 = cm_->get_loaded_controllers ()[1 ];
231
+
232
+ // Configure controllers
233
+ ASSERT_EQ (controller_interface::return_type::OK, cm_->configure_controller (controller_name1));
234
+ ASSERT_EQ (controller_interface::return_type::OK, cm_->configure_controller (controller_name2));
235
+
236
+ ASSERT_EQ (
237
+ lifecycle_msgs::msg::State::PRIMARY_STATE_INACTIVE,
238
+ abstract_test_controller1.c ->get_state ().id ());
239
+ ASSERT_EQ (
240
+ lifecycle_msgs::msg::State::PRIMARY_STATE_INACTIVE,
241
+ abstract_test_controller2.c ->get_state ().id ());
242
+
243
+ { // Test starting the first controller
244
+ RCLCPP_INFO (cm_->get_logger (), " Starting controller #1" );
245
+ std::vector<std::string> start_controllers = {controller_name1};
246
+ std::vector<std::string> stop_controllers = {};
247
+ auto switch_future = std::async (
248
+ std::launch::async, &controller_manager::ControllerManager::switch_controller, cm_,
249
+ start_controllers, stop_controllers, STRICT, true , rclcpp::Duration (0 , 0 ));
250
+ ASSERT_EQ (std::future_status::timeout, switch_future.wait_for (std::chrono::milliseconds (100 )))
251
+ << " switch_controller should be blocking until next update cycle" ;
252
+ ControllerManagerRunner cm_runner (this );
253
+ EXPECT_EQ (controller_interface::return_type::OK, switch_future.get ());
254
+ ASSERT_EQ (
255
+ lifecycle_msgs::msg::State::PRIMARY_STATE_INACTIVE,
256
+ abstract_test_controller1.c ->get_state ().id ());
257
+ ASSERT_EQ (
258
+ lifecycle_msgs::msg::State::PRIMARY_STATE_INACTIVE,
259
+ abstract_test_controller2.c ->get_state ().id ());
260
+ }
261
+
262
+ { // Test starting the second controller when the first is running
263
+ // Fails as they have the same command interface
264
+ RCLCPP_INFO (cm_->get_logger (), " Starting controller #2" );
265
+ std::vector<std::string> start_controllers = {controller_name2};
266
+ std::vector<std::string> stop_controllers = {};
267
+ auto switch_future = std::async (
268
+ std::launch::async, &controller_manager::ControllerManager::switch_controller, cm_,
269
+ start_controllers, stop_controllers, STRICT, true , rclcpp::Duration (0 , 0 ));
270
+ ASSERT_EQ (std::future_status::timeout, switch_future.wait_for (std::chrono::milliseconds (100 )))
271
+ << " switch_controller should be blocking until next update cycle" ;
272
+ ControllerManagerRunner cm_runner (this );
273
+ EXPECT_EQ (controller_interface::return_type::OK, switch_future.get ());
274
+ ASSERT_EQ (
275
+ lifecycle_msgs::msg::State::PRIMARY_STATE_INACTIVE,
276
+ abstract_test_controller1.c ->get_state ().id ());
277
+ ASSERT_EQ (
278
+ lifecycle_msgs::msg::State::PRIMARY_STATE_ACTIVE,
279
+ abstract_test_controller2.c ->get_state ().id ());
280
+ }
281
+ }
0 commit comments