Skip to content

Commit

Permalink
[CI] Backport #1636 #1668 and fix coverage on jammy (#1677) (#1693)
Browse files Browse the repository at this point in the history
* Add a pytest launch file to test ros2_control_node (#1636)
* [CI] Add coveragepy and remove ignore: test (#1668)

(cherry picked from commit 8b32c33)

Co-authored-by: Christoph Fröhlich <christophfroehlich@users.noreply.github.com>
  • Loading branch information
mergify[bot] and christophfroehlich committed Aug 19, 2024
1 parent 1634124 commit c2760b4
Show file tree
Hide file tree
Showing 6 changed files with 123 additions and 6 deletions.
2 changes: 0 additions & 2 deletions codecov.yml
Original file line number Diff line number Diff line change
Expand Up @@ -14,8 +14,6 @@ fixes:
comment:
layout: "diff, flags, files"
behavior: default
ignore:
- "**/test"
flags:
unittests:
paths:
Expand Down
5 changes: 5 additions & 0 deletions controller_manager/CMakeLists.txt
Original file line number Diff line number Diff line change
Expand Up @@ -204,6 +204,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
2 changes: 2 additions & 0 deletions controller_manager/package.xml
Original file line number Diff line number Diff line change
Expand Up @@ -29,6 +29,8 @@
<depend>std_msgs</depend>

<test_depend>ament_cmake_gmock</test_depend>
<test_depend>ament_cmake_pytest</test_depend>
<test_depend>python3-coverage</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)
14 changes: 10 additions & 4 deletions controller_manager/test/test_spawner_unspawner.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -28,6 +28,7 @@

using ::testing::_;
using ::testing::Return;
const char coveragepy_script[] = "python3 -m coverage run --append --branch";

using namespace std::chrono_literals;
class TestLoadController : public ControllerManagerFixture<controller_manager::ControllerManager>
Expand Down Expand Up @@ -68,14 +69,18 @@ class TestLoadController : public ControllerManagerFixture<controller_manager::C

int call_spawner(const std::string extra_args)
{
std::string spawner_script = "ros2 run controller_manager spawner ";
std::string spawner_script =
std::string(coveragepy_script) +
" $(ros2 pkg prefix controller_manager)/lib/controller_manager/spawner ";
return std::system((spawner_script + extra_args).c_str());
}

int call_unspawner(const std::string extra_args)
{
std::string spawner_script = "ros2 run controller_manager unspawner ";
return std::system((spawner_script + extra_args).c_str());
std::string unspawner_script =
std::string(coveragepy_script) +
" $(ros2 pkg prefix controller_manager)/lib/controller_manager/unspawner ";
return std::system((unspawner_script + extra_args).c_str());
}

TEST_F(TestLoadController, spawner_with_no_arguments_errors)
Expand Down Expand Up @@ -267,7 +272,8 @@ TEST_F(TestLoadController, unload_on_kill)
// timeout command will kill it after the specified time with signal SIGINT
std::stringstream ss;
ss << "timeout --signal=INT 5 "
<< "ros2 run controller_manager spawner "
<< std::string(coveragepy_script) +
" $(ros2 pkg prefix controller_manager)/lib/controller_manager/spawner "
<< "ctrl_3 -c test_controller_manager -t "
<< std::string(test_controller::TEST_CONTROLLER_CLASS_NAME) << " --unload-on-kill";

Expand Down

0 comments on commit c2760b4

Please sign in to comment.