diff --git a/controller_manager/CMakeLists.txt b/controller_manager/CMakeLists.txt index 3671179fae..5dea15c0d1 100644 --- a/controller_manager/CMakeLists.txt +++ b/controller_manager/CMakeLists.txt @@ -211,14 +211,6 @@ if(BUILD_TESTING) controller_manager_msgs ) - install(FILES test/test_controllers.yaml - DESTINATION test) - - find_package(launch_testing_ament_cmake REQUIRED) - add_launch_test(test/test_spawner_integration.py - TIMEOUT 180 - ) - find_package(ament_cmake_pytest REQUIRED) install(FILES test/test_ros2_control_node.yaml DESTINATION test) diff --git a/controller_manager/package.xml b/controller_manager/package.xml index b4b295656e..c0e02df044 100644 --- a/controller_manager/package.xml +++ b/controller_manager/package.xml @@ -32,10 +32,8 @@ ament_cmake_gmock ament_cmake_pytest hardware_interface_testing - launch_testing_ament_cmake python3-coverage ros2_control_test_assets - xacro ament_cmake diff --git a/controller_manager/test/test_controllers.yaml b/controller_manager/test/test_controllers.yaml deleted file mode 100644 index a465e81ad6..0000000000 --- a/controller_manager/test/test_controllers.yaml +++ /dev/null @@ -1,105 +0,0 @@ ---- -controller_manager: - ros__parameters: - update_rate: 100 - - joint_state_broadcaster0: - type: controller_manager/test_controller - joint_state_broadcaster1: - type: controller_manager/test_controller - joint_state_broadcaster2: - type: controller_manager/test_controller - joint_state_broadcaster3: - type: controller_manager/test_controller - joint_state_broadcaster4: - type: controller_manager/test_controller - joint_state_broadcaster5: - type: controller_manager/test_controller - joint_state_broadcaster6: - type: controller_manager/test_controller - joint_state_broadcaster7: - type: controller_manager/test_controller - joint_state_broadcaster8: - type: controller_manager/test_controller - joint_state_broadcaster9: - type: controller_manager/test_controller - joint_state_broadcaster10: - type: controller_manager/test_controller - joint_state_broadcaster11: - type: controller_manager/test_controller - joint_state_broadcaster12: - type: controller_manager/test_controller - joint_state_broadcaster13: - type: controller_manager/test_controller - joint_state_broadcaster14: - type: controller_manager/test_controller - joint_state_broadcaster15: - type: controller_manager/test_controller - joint_state_broadcaster16: - type: controller_manager/test_controller - joint_state_broadcaster17: - type: controller_manager/test_controller - joint_state_broadcaster18: - type: controller_manager/test_controller - joint_state_broadcaster19: - type: controller_manager/test_controller - joint_state_broadcaster20: - type: controller_manager/test_controller - joint_state_broadcaster21: - type: controller_manager/test_controller - joint_state_broadcaster22: - type: controller_manager/test_controller - joint_state_broadcaster23: - type: controller_manager/test_controller - joint_state_broadcaster24: - type: controller_manager/test_controller - joint_state_broadcaster25: - type: controller_manager/test_controller - joint_state_broadcaster26: - type: controller_manager/test_controller - joint_state_broadcaster27: - type: controller_manager/test_controller - joint_state_broadcaster28: - type: controller_manager/test_controller - joint_state_broadcaster29: - type: controller_manager/test_controller - joint_state_broadcaster30: - type: controller_manager/test_controller - joint_state_broadcaster31: - type: controller_manager/test_controller - joint_state_broadcaster32: - type: controller_manager/test_controller - joint_state_broadcaster33: - type: controller_manager/test_controller - joint_state_broadcaster34: - type: controller_manager/test_controller - joint_state_broadcaster35: - type: controller_manager/test_controller - joint_state_broadcaster36: - type: controller_manager/test_controller - joint_state_broadcaster37: - type: controller_manager/test_controller - joint_state_broadcaster38: - type: controller_manager/test_controller - joint_state_broadcaster39: - type: controller_manager/test_controller - joint_state_broadcaster40: - type: controller_manager/test_controller - joint_state_broadcaster41: - type: controller_manager/test_controller - joint_state_broadcaster42: - type: controller_manager/test_controller - joint_state_broadcaster43: - type: controller_manager/test_controller - joint_state_broadcaster44: - type: controller_manager/test_controller - joint_state_broadcaster45: - type: controller_manager/test_controller - joint_state_broadcaster46: - type: controller_manager/test_controller - joint_state_broadcaster47: - type: controller_manager/test_controller - joint_state_broadcaster48: - type: controller_manager/test_controller - joint_state_broadcaster49: - type: controller_manager/test_controller diff --git a/controller_manager/test/test_spawner_integration.py b/controller_manager/test/test_spawner_integration.py deleted file mode 100644 index 73299bf000..0000000000 --- a/controller_manager/test/test_spawner_integration.py +++ /dev/null @@ -1,194 +0,0 @@ -# Copyright 2024 FZI Forschungszentrum Informatik -# -# Licensed under the Apache License, Version 2.0 (the "License"); -# you may not use this file except in compliance with the License. -# You may obtain a copy of the License at -# -# http://www.apache.org/licenses/LICENSE-2.0 -# -# Unless required by applicable law or agreed to in writing, software -# distributed under the License is distributed on an "AS IS" BASIS, -# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. -# See the License for the specific language governing permissions and -# limitations under the License. -# -# Author: Felix Exner - -import time -import pytest -import unittest - -import launch -import launch_testing.actions - -from launch.substitutions import ( - Command, - FindExecutable, - PathJoinSubstitution, -) -from launch_ros.substitutions import FindPackageShare -from launch_ros.parameter_descriptions import ParameterFile - -from launch_ros.actions import Node as LaunchNode - -# Imports for tests -import rclpy -from rclpy.node import Node -import logging - -from controller_manager_msgs.srv import ListControllers - -CONTROLLER_SPAWNER_TIMEOUT = "10" - -active_controllers = [ - "joint_state_broadcaster0", - "joint_state_broadcaster1", - "joint_state_broadcaster2", - "joint_state_broadcaster3", - "joint_state_broadcaster4", - "joint_state_broadcaster5", - "joint_state_broadcaster6", - "joint_state_broadcaster7", - "joint_state_broadcaster8", - "joint_state_broadcaster9", - "joint_state_broadcaster10", - "joint_state_broadcaster11", - "joint_state_broadcaster12", - "joint_state_broadcaster13", - "joint_state_broadcaster14", - "joint_state_broadcaster15", - "joint_state_broadcaster16", - "joint_state_broadcaster17", - "joint_state_broadcaster18", - "joint_state_broadcaster19", - "joint_state_broadcaster20", - "joint_state_broadcaster21", - "joint_state_broadcaster22", - "joint_state_broadcaster23", - "joint_state_broadcaster24", - "joint_state_broadcaster25", - "joint_state_broadcaster26", - "joint_state_broadcaster27", - "joint_state_broadcaster28", - "joint_state_broadcaster29", - "joint_state_broadcaster30", - "joint_state_broadcaster31", - "joint_state_broadcaster32", - "joint_state_broadcaster33", - "joint_state_broadcaster34", - "joint_state_broadcaster35", - "joint_state_broadcaster36", - "joint_state_broadcaster37", - "joint_state_broadcaster38", - "joint_state_broadcaster39", - "joint_state_broadcaster40", - "joint_state_broadcaster41", - "joint_state_broadcaster42", - "joint_state_broadcaster43", - "joint_state_broadcaster44", - "joint_state_broadcaster45", - "joint_state_broadcaster46", - "joint_state_broadcaster47", - "joint_state_broadcaster48", - "joint_state_broadcaster49", -] - - -def controller_spawner(controllers, active=True): - inactive_flags = ["--inactive"] if not active else [] - return LaunchNode( - package="controller_manager", - executable="spawner", - arguments=[ - "--controller-manager", - "/controller_manager", - "--controller-manager-timeout", - CONTROLLER_SPAWNER_TIMEOUT, - ] - + inactive_flags - + controllers, - ) - - -@pytest.mark.launch_test -def generate_test_description(): - robot_description_content = Command( - [ - PathJoinSubstitution([FindExecutable(name="xacro")]), - " ", - PathJoinSubstitution( - [ - FindPackageShare("ros2_control_test_assets"), - "urdf", - "test_description_mock.urdf", - ] - ), - ] - ) - robot_state_publisher_node = LaunchNode( - package="robot_state_publisher", - executable="robot_state_publisher", - output="both", - parameters=[{"robot_description": robot_description_content}], - ) - - control_node = LaunchNode( - package="controller_manager", - executable="ros2_control_node", - parameters=[ - ParameterFile( - PathJoinSubstitution( - [FindPackageShare("controller_manager"), "test", "test_controllers.yaml"] - ) - ) - ], - output="screen", - ) - - spawners = [controller_spawner([x]) for x in active_controllers] - - return launch.LaunchDescription( - [ - robot_state_publisher_node, - control_node, - launch_testing.actions.ReadyToTest(), - ] - + spawners - ) - - -class TestControllersRunning(unittest.TestCase): - @classmethod - def setUpClass(cls): - # Initialize the ROS context - rclpy.init() - cls.node = Node("controller_spawner_test") - - def _wait_for_service(self, srv_name, srv_type, timeout=10): - client = self.node.create_client(srv_type, srv_name) - - logging.info("Waiting for service '%s' with timeout %fs...", srv_name, timeout) - if client.wait_for_service(timeout) is False: - raise Exception(f"Could not reach service '{srv_name}' within timeout of {timeout}") - logging.info(" Successfully connected to service '%s'", srv_name) - - return client - - def test_all_controllers_available(self): - client = self._wait_for_service( - srv_name="controller_manager/list_controllers", srv_type=ListControllers - ) - # This is basically a dirty hack. It would be better to add events to all the spawners - # exiting and emit ReadyToTest() only after all of them have quit. One problem there: They - # do not necessarily quit, but can get into a deadlock waiting for a service response. - time.sleep(30) - request = ListControllers.Request() - future = client.call_async(request) - rclpy.spin_until_future_complete(self.node, future) - if future.result() is None: - raise Exception( - f"Error while calling service '{client.srv_name}': {future.exception()}" - ) - - result = future.result() - self.assertEqual(len(result.controller), len(active_controllers)) diff --git a/controller_manager/test/test_spawner_unspawner.cpp b/controller_manager/test/test_spawner_unspawner.cpp index 3edf770436..3de8708235 100644 --- a/controller_manager/test/test_spawner_unspawner.cpp +++ b/controller_manager/test/test_spawner_unspawner.cpp @@ -374,6 +374,32 @@ TEST_F(TestLoadController, spawner_test_fallback_controllers) } } +TEST_F(TestLoadController, spawner_with_many_controllers) +{ + std::stringstream ss; + const size_t num_controllers = 50; + const std::string controller_base_name = "ctrl_"; + for (size_t i = 0; i < num_controllers; i++) + { + std::string controller_name = controller_base_name + std::to_string(static_cast(i)); + cm_->set_parameter( + rclcpp::Parameter(controller_name + ".type", test_controller::TEST_CONTROLLER_CLASS_NAME)); + ss << controller_name << " "; + } + + ControllerManagerRunner cm_runner(this); + EXPECT_EQ(call_spawner(ss.str() + " -c test_controller_manager"), 0); + + ASSERT_EQ(cm_->get_loaded_controllers().size(), num_controllers); + + for (size_t i = 0; i < num_controllers; i++) + { + auto ctrl = cm_->get_loaded_controllers()[i]; + ASSERT_EQ(ctrl.info.type, test_controller::TEST_CONTROLLER_CLASS_NAME); + ASSERT_EQ(ctrl.c->get_state().id(), lifecycle_msgs::msg::State::PRIMARY_STATE_ACTIVE); + } +} + class TestLoadControllerWithoutRobotDescription : public ControllerManagerFixture { diff --git a/ros2_control_test_assets/CMakeLists.txt b/ros2_control_test_assets/CMakeLists.txt index 8182766b44..d1bb895eed 100644 --- a/ros2_control_test_assets/CMakeLists.txt +++ b/ros2_control_test_assets/CMakeLists.txt @@ -14,10 +14,6 @@ install( DIRECTORY include/ DESTINATION include/ros2_control_test_assets ) -install( - DIRECTORY urdf - DESTINATION share/${PROJECT_NAME} -) install(TARGETS ros2_control_test_assets EXPORT export_ros2_control_test_assets ARCHIVE DESTINATION lib diff --git a/ros2_control_test_assets/urdf/test_description_mock.urdf b/ros2_control_test_assets/urdf/test_description_mock.urdf deleted file mode 100644 index 715de97540..0000000000 --- a/ros2_control_test_assets/urdf/test_description_mock.urdf +++ /dev/null @@ -1,91 +0,0 @@ - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - mock_components/GenericSystem - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -