Skip to content

Commit 872029c

Browse files
Add a pytest launch file to test ros2_control_node (ros-controls#1636)
1 parent 3eae727 commit 872029c

File tree

4 files changed

+112
-0
lines changed

4 files changed

+112
-0
lines changed

controller_manager/CMakeLists.txt

Lines changed: 5 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -209,6 +209,11 @@ if(BUILD_TESTING)
209209
ament_target_dependencies(test_hardware_management_srvs
210210
controller_manager_msgs
211211
)
212+
213+
find_package(ament_cmake_pytest REQUIRED)
214+
install(FILES test/test_ros2_control_node.yaml
215+
DESTINATION test)
216+
ament_add_pytest_test(test_ros2_control_node test/test_ros2_control_node_launch.py)
212217
endif()
213218

214219
install(

controller_manager/package.xml

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -30,6 +30,7 @@
3030
<depend>std_msgs</depend>
3131

3232
<test_depend>ament_cmake_gmock</test_depend>
33+
<test_depend>ament_cmake_pytest</test_depend>
3334
<test_depend>hardware_interface_testing</test_depend>
3435
<test_depend>ros2_control_test_assets</test_depend>
3536

Lines changed: 11 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,11 @@
1+
controller_manager:
2+
ros__parameters:
3+
update_rate: 100 # Hz
4+
5+
ctrl_with_parameters_and_type:
6+
ros__parameters:
7+
type: "controller_manager/test_controller"
8+
joint_names: ["joint0"]
9+
10+
joint_state_broadcaster:
11+
type: joint_state_broadcaster/JointStateBroadcaster
Lines changed: 95 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,95 @@
1+
# Copyright (c) 2024 AIT - Austrian Institute of Technology GmbH
2+
#
3+
# Redistribution and use in source and binary forms, with or without
4+
# modification, are permitted provided that the following conditions are met:
5+
#
6+
# * Redistributions of source code must retain the above copyright
7+
# notice, this list of conditions and the following disclaimer.
8+
#
9+
# * Redistributions in binary form must reproduce the above copyright
10+
# notice, this list of conditions and the following disclaimer in the
11+
# documentation and/or other materials provided with the distribution.
12+
#
13+
# * Neither the name of the {copyright_holder} nor the names of its
14+
# contributors may be used to endorse or promote products derived from
15+
# this software without specific prior written permission.
16+
#
17+
# THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS"
18+
# AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
19+
# IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
20+
# ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER OR CONTRIBUTORS BE
21+
# LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR
22+
# CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF
23+
# SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS
24+
# INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN
25+
# CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE)
26+
# ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE
27+
# POSSIBILITY OF SUCH DAMAGE.
28+
#
29+
# Author: Christoph Froehlich
30+
31+
import pytest
32+
import unittest
33+
import time
34+
35+
from launch import LaunchDescription
36+
from launch.substitutions import PathJoinSubstitution
37+
from launch_ros.substitutions import FindPackageShare
38+
from launch_testing.actions import ReadyToTest
39+
40+
import launch_testing.markers
41+
import rclpy
42+
import launch_ros.actions
43+
from rclpy.node import Node
44+
45+
46+
# Executes the given launch file and checks if all nodes can be started
47+
@pytest.mark.launch_test
48+
def generate_test_description():
49+
50+
robot_controllers = PathJoinSubstitution(
51+
[
52+
FindPackageShare("controller_manager"),
53+
"test",
54+
"test_ros2_control_node.yaml",
55+
]
56+
)
57+
58+
control_node = launch_ros.actions.Node(
59+
package="controller_manager",
60+
executable="ros2_control_node",
61+
parameters=[robot_controllers],
62+
output="both",
63+
)
64+
65+
return LaunchDescription([control_node, ReadyToTest()])
66+
67+
68+
# This is our test fixture. Each method is a test case.
69+
# These run alongside the processes specified in generate_test_description()
70+
class TestFixture(unittest.TestCase):
71+
72+
def setUp(self):
73+
rclpy.init()
74+
self.node = Node("test_node")
75+
76+
def tearDown(self):
77+
self.node.destroy_node()
78+
rclpy.shutdown()
79+
80+
def test_node_start(self):
81+
start = time.time()
82+
found = False
83+
while time.time() - start < 2.0 and not found:
84+
found = "controller_manager" in self.node.get_node_names()
85+
time.sleep(0.1)
86+
assert found, "controller_manager not found!"
87+
88+
89+
@launch_testing.post_shutdown_test()
90+
# These tests are run after the processes in generate_test_description() have shutdown.
91+
class TestDescriptionCraneShutdown(unittest.TestCase):
92+
93+
def test_exit_codes(self, proc_info):
94+
"""Check if the processes exited normally."""
95+
launch_testing.asserts.assertExitCodes(proc_info)

0 commit comments

Comments
 (0)