Skip to content

Commit

Permalink
Add a pytest launch file to test ros2_control_node (ros-controls#1636)
Browse files Browse the repository at this point in the history
  • Loading branch information
christophfroehlich authored Jul 27, 2024
1 parent 3eae727 commit 872029c
Show file tree
Hide file tree
Showing 4 changed files with 112 additions and 0 deletions.
5 changes: 5 additions & 0 deletions controller_manager/CMakeLists.txt
Original file line number Diff line number Diff line change
Expand Up @@ -209,6 +209,11 @@ if(BUILD_TESTING)
ament_target_dependencies(test_hardware_management_srvs
controller_manager_msgs
)

find_package(ament_cmake_pytest REQUIRED)
install(FILES test/test_ros2_control_node.yaml
DESTINATION test)
ament_add_pytest_test(test_ros2_control_node test/test_ros2_control_node_launch.py)
endif()

install(
Expand Down
1 change: 1 addition & 0 deletions controller_manager/package.xml
Original file line number Diff line number Diff line change
Expand Up @@ -30,6 +30,7 @@
<depend>std_msgs</depend>

<test_depend>ament_cmake_gmock</test_depend>
<test_depend>ament_cmake_pytest</test_depend>
<test_depend>hardware_interface_testing</test_depend>
<test_depend>ros2_control_test_assets</test_depend>

Expand Down
11 changes: 11 additions & 0 deletions controller_manager/test/test_ros2_control_node.yaml
Original file line number Diff line number Diff line change
@@ -0,0 +1,11 @@
controller_manager:
ros__parameters:
update_rate: 100 # Hz

ctrl_with_parameters_and_type:
ros__parameters:
type: "controller_manager/test_controller"
joint_names: ["joint0"]

joint_state_broadcaster:
type: joint_state_broadcaster/JointStateBroadcaster
95 changes: 95 additions & 0 deletions controller_manager/test/test_ros2_control_node_launch.py
Original file line number Diff line number Diff line change
@@ -0,0 +1,95 @@
# Copyright (c) 2024 AIT - Austrian Institute of Technology GmbH
#
# Redistribution and use in source and binary forms, with or without
# modification, are permitted provided that the following conditions are met:
#
# * Redistributions of source code must retain the above copyright
# notice, this list of conditions and the following disclaimer.
#
# * Redistributions in binary form must reproduce the above copyright
# notice, this list of conditions and the following disclaimer in the
# documentation and/or other materials provided with the distribution.
#
# * Neither the name of the {copyright_holder} nor the names of its
# contributors may be used to endorse or promote products derived from
# this software without specific prior written permission.
#
# THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS"
# AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
# IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
# ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER OR CONTRIBUTORS BE
# LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR
# CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF
# SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS
# INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN
# CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE)
# ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE
# POSSIBILITY OF SUCH DAMAGE.
#
# Author: Christoph Froehlich

import pytest
import unittest
import time

from launch import LaunchDescription
from launch.substitutions import PathJoinSubstitution
from launch_ros.substitutions import FindPackageShare
from launch_testing.actions import ReadyToTest

import launch_testing.markers
import rclpy
import launch_ros.actions
from rclpy.node import Node


# Executes the given launch file and checks if all nodes can be started
@pytest.mark.launch_test
def generate_test_description():

robot_controllers = PathJoinSubstitution(
[
FindPackageShare("controller_manager"),
"test",
"test_ros2_control_node.yaml",
]
)

control_node = launch_ros.actions.Node(
package="controller_manager",
executable="ros2_control_node",
parameters=[robot_controllers],
output="both",
)

return LaunchDescription([control_node, ReadyToTest()])


# This is our test fixture. Each method is a test case.
# These run alongside the processes specified in generate_test_description()
class TestFixture(unittest.TestCase):

def setUp(self):
rclpy.init()
self.node = Node("test_node")

def tearDown(self):
self.node.destroy_node()
rclpy.shutdown()

def test_node_start(self):
start = time.time()
found = False
while time.time() - start < 2.0 and not found:
found = "controller_manager" in self.node.get_node_names()
time.sleep(0.1)
assert found, "controller_manager not found!"


@launch_testing.post_shutdown_test()
# These tests are run after the processes in generate_test_description() have shutdown.
class TestDescriptionCraneShutdown(unittest.TestCase):

def test_exit_codes(self, proc_info):
"""Check if the processes exited normally."""
launch_testing.asserts.assertExitCodes(proc_info)

0 comments on commit 872029c

Please sign in to comment.