Skip to content

Commit 27e3b68

Browse files
committed
Changes - Add tests for launch_utils of controller manager ros-controls#2147 PR(ros-controls#2768)
1 parent ef3930e commit 27e3b68

11 files changed

+98
-118
lines changed

controller_manager/CMakeLists.txt

Lines changed: 3 additions & 21 deletions
Original file line numberDiff line numberDiff line change
@@ -247,30 +247,12 @@ if(BUILD_TESTING)
247247
find_package(launch_testing_ament_cmake REQUIRED)
248248
find_package(rclpy REQUIRED)
249249
install(FILES test/test_ros2_control_node.yaml
250-
test/test_controller_load.yaml
251-
test/test_ros2_control_node_combined.yaml
252250
DESTINATION test)
253251
ament_add_pytest_test(test_ros2_control_node test/test_ros2_control_node_launch.py)
254252
ament_add_pytest_test(test_test_utils test/test_test_utils.py)
255-
ament_add_pytest_test(test_launch_utils_unit test/test_launch_utils_unit.py
256-
APPEND_ENV AMENT_PREFIX_PATH=${ament_index_build_path}
257-
PYTHONPATH=${CMAKE_CURRENT_BINARY_DIR}:${CMAKE_CURRENT_SOURCE_DIR}:${PYTHONPATH}
258-
)
259-
# ----------------------------------------------------------------------------
260-
# Integration tests for individual launch_utils entry points
261-
# ----------------------------------------------------------------------------
262-
ament_add_pytest_test(test_launch_utils_integration_list
263-
test/test_launch_utils_integration_list.py
264-
TIMEOUT 60
265-
)
266-
ament_add_pytest_test(test_launch_utils_integration_dict
267-
test/test_launch_utils_integration_dict.py
268-
TIMEOUT 60
269-
)
270-
ament_add_pytest_test(test_launch_utils_integration_load
271-
test/test_launch_utils_integration_load.py
272-
TIMEOUT 60
273-
)
253+
254+
# Now include the launch_utils subfolder
255+
add_subdirectory(test/test_launch_utils)
274256

275257
endif()
276258

controller_manager/test/test_controller3.yaml

Lines changed: 0 additions & 8 deletions
This file was deleted.

controller_manager/test/test_joint_state_broadcast.yaml

Lines changed: 0 additions & 7 deletions
This file was deleted.
Lines changed: 42 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,42 @@
1+
# This subdirectory handles pytest-based launch tests for controller_manager
2+
3+
find_package(ament_cmake_pytest REQUIRED)
4+
find_package(launch_testing_ament_cmake REQUIRED)
5+
find_package(rclpy REQUIRED)
6+
7+
# Install YAML test files
8+
#
9+
install(
10+
FILES
11+
test_controller_load.yaml
12+
test_ros2_control_node_combined.yaml
13+
DESTINATION test
14+
)
15+
16+
# Make sure test files get installed into the test tree
17+
install(
18+
FILES
19+
test_launch_utils_unit.py
20+
test_launch_utils_integration_list.py
21+
test_launch_utils_integration_dict.py
22+
test_launch_utils_integration_load.py
23+
DESTINATION test
24+
)
25+
26+
# Register each test with ament
27+
ament_add_pytest_test(test_launch_utils_unit test_launch_utils_unit.py
28+
APPEND_ENV AMENT_PREFIX_PATH=${ament_index_build_path}
29+
PYTHONPATH=${CMAKE_CURRENT_BINARY_DIR}:${CMAKE_CURRENT_SOURCE_DIR}:${PYTHONPATH}
30+
)
31+
ament_add_pytest_test(test_launch_utils_integration_list
32+
test_launch_utils_integration_list.py
33+
TIMEOUT 60
34+
)
35+
ament_add_pytest_test(test_launch_utils_integration_dict
36+
test_launch_utils_integration_dict.py
37+
TIMEOUT 60
38+
)
39+
ament_add_pytest_test(test_launch_utils_integration_load
40+
test_launch_utils_integration_load.py
41+
TIMEOUT 60
42+
)

controller_manager/test/test_launch_utils_integration_dict.py renamed to controller_manager/test/test_launch_utils/test_launch_utils_integration_dict.py

Lines changed: 22 additions & 19 deletions
Original file line numberDiff line numberDiff line change
@@ -15,15 +15,14 @@
1515

1616
import pytest
1717
import unittest
18-
import os
1918
import tempfile
2019
import time
20+
from pathlib import Path
2121

2222
from ament_index_python.packages import get_package_share_directory, get_package_prefix
2323
from launch import LaunchDescription
2424
import launch_testing
2525
from launch_testing.actions import ReadyToTest
26-
import launch_testing.markers
2726
import launch_ros.actions
2827

2928
import rclpy
@@ -45,23 +44,27 @@ def generate_test_description():
4544
temp_dir = tempfile.mkdtemp()
4645
print(f"Creating test files in: {temp_dir}")
4746

48-
# Get URDF, without involving xacro
49-
urdf = os.path.join(
50-
get_package_share_directory("ros2_control_test_assets"),
51-
"urdf",
52-
"test_hardware_components.urdf",
47+
# URDF path (pathlib version, no xacro)
48+
urdf = (
49+
Path(get_package_share_directory("ros2_control_test_assets"))
50+
/ "urdf"
51+
/ "test_hardware_components.urdf"
5352
)
53+
5454
with open(urdf) as infp:
5555
robot_description_content = infp.read()
5656
robot_description = {"robot_description": robot_description_content}
5757

58-
robot_controllers = os.path.join(
59-
get_package_prefix("controller_manager"), "test", "test_ros2_control_node_combined.yaml"
58+
# Path to combined YAML
59+
robot_controllers = (
60+
Path(get_package_prefix("controller_manager"))
61+
/ "test"
62+
/ "test_ros2_control_node_combined.yaml"
6063
)
6164

62-
# Verify both files exist
63-
assert os.path.isfile(robot_controllers), f"Controller config not created: {robot_controllers}"
64-
assert os.path.isfile(urdf), f"URDF not created: {urdf}"
65+
# Verify files exist (Path method)
66+
assert robot_controllers.is_file(), f"Controller config not found: {robot_controllers}"
67+
assert urdf.is_file(), f"URDF not found: {urdf}"
6568

6669
robot_state_pub_node = launch_ros.actions.Node(
6770
package="robot_state_publisher",
@@ -74,16 +77,16 @@ def generate_test_description():
7477
control_node = launch_ros.actions.Node(
7578
package="controller_manager",
7679
executable="ros2_control_node",
77-
parameters=[robot_controllers], # Use the combined config file
80+
parameters=[str(robot_controllers)], # Use the combined config file
7881
output="both",
7982
)
8083

8184
# The dictionary keys are the controller names to be spawned/started.
8285
# Values can be empty lists since config is provided via the main YAML.
8386
ctrl_dict = {
84-
"joint_state_broadcaster": [robot_controllers],
85-
"ctrl_with_parameters_and_type": [robot_controllers],
86-
"controller3": [robot_controllers],
87+
"joint_state_broadcaster": [str(robot_controllers)],
88+
"controller1": [str(robot_controllers)],
89+
"controller2": [str(robot_controllers)],
8790
}
8891
controller_list = list(ctrl_dict.keys())
8992

@@ -103,7 +106,7 @@ def generate_test_description():
103106
# Return tuple with launch description and test context
104107
return ld, {
105108
"controller_list": controller_list, # Key name updated to match the test function
106-
"robot_controllers": str(robot_controllers),
109+
"robot_controllers": robot_controllers,
107110
"urdf_file": urdf,
108111
"temp_dir": temp_dir,
109112
}
@@ -224,15 +227,15 @@ def test_exit_codes(self, proc_info):
224227

225228
print("[POST-SHUTDOWN] ? All processes exited as expected")
226229

227-
def test_cleanup_temp_files(self, temp_dir, robot_controllers, urdf_file):
230+
def test_cleanup_temp_files(self, temp_dir):
228231
"""Clean up temporary test files."""
229232
import shutil
230233

231234
print(f"\n[CLEANUP] Removing temporary directory: {temp_dir}")
232235

233236
# The original clean-up logic was commented out, enabling it for safety
234237
try:
235-
if os.path.exists(temp_dir):
238+
if temp_dir.exists():
236239
shutil.rmtree(temp_dir)
237240

238241
print("[CLEANUP] ? Temporary files removed")

controller_manager/test/test_launch_utils_integration_list.py renamed to controller_manager/test/test_launch_utils/test_launch_utils_integration_list.py

Lines changed: 17 additions & 16 deletions
Original file line numberDiff line numberDiff line change
@@ -15,15 +15,14 @@
1515

1616
import pytest
1717
import unittest
18-
import os
1918
import time
2019
import tempfile
20+
from pathlib import Path
2121

2222
from ament_index_python.packages import get_package_share_directory, get_package_prefix
2323
from launch import LaunchDescription
2424
import launch_testing
2525
from launch_testing.actions import ReadyToTest
26-
import launch_testing.markers
2726
import launch_ros.actions
2827

2928
import rclpy
@@ -44,22 +43,24 @@ def generate_test_description():
4443
print(f"Creating test files in: {temp_dir}")
4544

4645
# Get URDF, without involving xacro
47-
urdf = os.path.join(
48-
get_package_share_directory("ros2_control_test_assets"),
49-
"urdf",
50-
"test_hardware_components.urdf",
46+
urdf = (
47+
Path(get_package_share_directory("ros2_control_test_assets"))
48+
/ "urdf"
49+
/ "test_hardware_components.urdf"
5150
)
5251
with open(urdf) as infp:
5352
robot_description_content = infp.read()
5453
robot_description = {"robot_description": robot_description_content}
5554

56-
robot_controllers = os.path.join(
57-
get_package_prefix("controller_manager"), "test", "test_ros2_control_node_combined.yaml"
55+
robot_controllers = (
56+
Path(get_package_prefix("controller_manager"))
57+
/ "test"
58+
/ "test_ros2_control_node_combined.yaml"
5859
)
5960

60-
# Verify both files exist
61-
assert os.path.isfile(robot_controllers), f"Controller config not created: {robot_controllers}"
62-
assert os.path.isfile(urdf), f"URDF not created: {urdf}"
61+
# Verify files exist
62+
assert robot_controllers.is_file(), f"Controller config missing: {robot_controllers}"
63+
assert urdf.is_file(), f"URDF missing: {urdf}"
6364

6465
robot_state_pub_node = launch_ros.actions.Node(
6566
package="robot_state_publisher",
@@ -72,20 +73,20 @@ def generate_test_description():
7273
control_node = launch_ros.actions.Node(
7374
package="controller_manager",
7475
executable="ros2_control_node",
75-
parameters=[robot_controllers],
76+
parameters=[str(robot_controllers)],
7677
output="both",
7778
)
7879

7980
# ===== DEFINE CONTROLLERS TO SPAWN =====
80-
controller_list = ["joint_state_broadcaster", "ctrl_with_parameters_and_type", "controller3"]
81+
controller_list = ["joint_state_broadcaster", "controller1", "controller2"]
8182

8283
# ===== GENERATE SPAWNER =====
8384
print(f"Spawning controllers: {controller_list}")
8485
print(f"Using config file: {robot_controllers}")
8586

8687
spawner_ld = generate_controllers_spawner_launch_description(
8788
controller_names=controller_list.copy(),
88-
controller_params_files=[robot_controllers],
89+
controller_params_files=[str(robot_controllers)],
8990
)
9091

9192
# ===== CREATE LAUNCH DESCRIPTION =====
@@ -217,14 +218,14 @@ def test_exit_codes(self, proc_info):
217218

218219
print("[POST-SHUTDOWN] ? All processes exited as expected")
219220

220-
def test_cleanup_temp_files(self, temp_dir, robot_controllers, urdf_file):
221+
def test_cleanup_temp_files(self, temp_dir):
221222
"""Clean up temporary test files."""
222223
import shutil
223224

224225
print(f"\n[CLEANUP] Removing temporary directory: {temp_dir}")
225226

226227
try:
227-
if os.path.exists(temp_dir):
228+
if temp_dir.exists():
228229
shutil.rmtree(temp_dir)
229230

230231
print("[CLEANUP] ? Temporary files removed")

controller_manager/test/test_launch_utils_integration_load.py renamed to controller_manager/test/test_launch_utils/test_launch_utils_integration_load.py

Lines changed: 11 additions & 13 deletions
Original file line numberDiff line numberDiff line change
@@ -15,15 +15,13 @@
1515

1616
import pytest
1717
import unittest
18-
import os
1918
import tempfile
20-
19+
from pathlib import Path
2120
from ament_index_python.packages import get_package_share_directory, get_package_prefix
2221
from launch import LaunchDescription
2322
import launch_testing
2423
from launch_testing.actions import ReadyToTest
2524
import launch_testing.asserts
26-
import launch_testing.markers
2725
import launch_ros.actions
2826

2927
import rclpy
@@ -67,21 +65,21 @@ def generate_test_description():
6765
print(f"Creating test files in: {temp_dir}")
6866

6967
# Get URDF, without involving xacro
70-
urdf = os.path.join(
71-
get_package_share_directory("ros2_control_test_assets"),
72-
"urdf",
73-
"test_hardware_components.urdf",
68+
urdf = (
69+
Path(get_package_share_directory("ros2_control_test_assets"))
70+
/ "urdf"
71+
/ "test_hardware_components.urdf"
7472
)
7573
with open(urdf) as infp:
7674
robot_description_content = infp.read()
7775
robot_description = {"robot_description": robot_description_content}
7876

79-
robot_controllers = os.path.join(
80-
get_package_prefix("controller_manager"), "test", "test_controller_load.yaml"
77+
robot_controllers = (
78+
Path(get_package_prefix("controller_manager")) / "test" / "test_controller_load.yaml"
8179
)
8280

8381
# Verify both files exist
84-
assert os.path.isfile(robot_controllers), f"Controller config not created: {robot_controllers}"
82+
assert robot_controllers.is_file(), f"Controller config not created: {robot_controllers}"
8583

8684
robot_state_pub_node = launch_ros.actions.Node(
8785
package="robot_state_publisher",
@@ -94,15 +92,15 @@ def generate_test_description():
9492
control_node = launch_ros.actions.Node(
9593
package="controller_manager",
9694
executable="ros2_control_node",
97-
parameters=[robot_controllers],
95+
parameters=[str(robot_controllers)],
9896
output="both",
9997
)
10098

10199
print(f"Using config file: {robot_controllers}")
102100

103101
spawner_action = generate_load_controller_launch_description(
104102
controller_name="test_controller_load",
105-
controller_params_file=[robot_controllers],
103+
controller_params_file=[str(robot_controllers)],
106104
)
107105

108106
ld = LaunchDescription(
@@ -117,7 +115,7 @@ def generate_test_description():
117115
return ld, {
118116
"temp_dir": temp_dir,
119117
"controller_name": "test_controller_load",
120-
"urdf_file": urdf,
118+
"urdf_file": str(urdf),
121119
}
122120

123121

controller_manager/test/test_ros2_control_node_combined.yaml renamed to controller_manager/test/test_launch_utils/test_ros2_control_node_combined.yaml

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -11,12 +11,12 @@ forward_position_controller:
1111
type: position_controllers/JointGroupPositionController
1212
joints: ["joint1"]
1313

14-
ctrl_with_parameters_and_type:
14+
controller1:
1515
ros__parameters:
1616
type: "controller_manager/test_controller"
1717
joint_names: ["joint1"]
1818

19-
controller3:
19+
controller2:
2020
ros__parameters:
2121
type: "controller_manager/test_controller"
2222
joint_names: ["joint3"]

0 commit comments

Comments
 (0)