diff --git a/.github/workflows/build.yaml b/.github/workflows/build.yaml index 8829ee50..e6242318 100644 --- a/.github/workflows/build.yaml +++ b/.github/workflows/build.yaml @@ -16,24 +16,21 @@ jobs: strategy: fail-fast: false matrix: - include: - # Rolling (source) - - ROS_DISTRO: rolling - BUILD_TYPE: source - # Jazzy (binary) - - ROS_DISTRO: jazzy - BUILD_TYPE: binary - # Iron (binary) - - ROS_DISTRO: iron - BUILD_TYPE: binary + ROS_DISTRO: [rolling, jazzy, iron] + BUILD_TYPE: [source, binary] + exclude: + - BUILD_TYPE: ${{ github.event_name != 'schedule' && 'source' || '' }} env: ROS2_REPOS_FILE_URL: 'https://raw.githubusercontent.com/ros2/ros2/${{ matrix.ROS_DISTRO }}/ros2.repos' + RMW_MIDDLEWARE_TEST_PACKAGES: 'test_rclcpp test_communication rcl' runs-on: ubuntu-latest container: image: ${{ matrix.BUILD_TYPE == 'binary' && format('ros:{0}-ros-base', matrix.ROS_DISTRO) || 'ubuntu:noble' }} steps: - uses: ros-tooling/setup-ros@v0.7 if: ${{ matrix.BUILD_TYPE == 'source' }} + with: + use-ros2-testing: true - name: Install Coverage Tools if: ${{ matrix.BUILD_TYPE == 'binary' }} run: sudo apt update && sudo apt install -y python3-colcon-coveragepy-result python3-colcon-lcov-result lcov @@ -42,7 +39,28 @@ jobs: uses: ros-tooling/action-ros-ci@v0.3 with: package-name: | + ${{ matrix.BUILD_TYPE == 'source' && env.RMW_MIDDLEWARE_TEST_PACKAGES || '' }} rmw_zenoh_cpp zenoh_c_vendor + colcon-defaults: | + { + "build": { + "cmake-args": [ + "-DSKIP_MULTI_RMW_TESTS=ON" + ] + } + } target-ros2-distro: ${{ matrix.ROS_DISTRO }} vcs-repo-file-url: ${{ matrix.BUILD_TYPE == 'source' && env.ROS2_REPOS_FILE_URL || '' }} + skip-tests: true + - name: Run system_tests + if: ${{ matrix.BUILD_TYPE == 'source' }} + run: | + cd ${{ steps.action-ros-ci.outputs.ros-workspace-directory-name }} + . install/setup.sh + launch_test install/rmw_zenoh_cpp/test/rmw_zenoh_integration.test.py 'selected_system_tests:=${{ env.RMW_MIDDLEWARE_TEST_PACKAGES }}' + - uses: actions/upload-artifact@v3 + if: ${{ matrix.BUILD_TYPE == 'source' }} + with: + name: colcon-logs-${{ matrix.ROS_DISTRO }}-latest + path: ${{ steps.action-ros-ci.outputs.ros-workspace-directory-name }}/log diff --git a/rmw_zenoh_cpp/CMakeLists.txt b/rmw_zenoh_cpp/CMakeLists.txt index 4ecfe360..73731e98 100644 --- a/rmw_zenoh_cpp/CMakeLists.txt +++ b/rmw_zenoh_cpp/CMakeLists.txt @@ -97,6 +97,9 @@ if(BUILD_TESTING) ament_lint_cmake() ament_uncrustify(EXCLUDE ${_linter_excludes}) ament_xmllint() + + install(FILES test/rmw_zenoh_integration.test.py + DESTINATION test) endif() install( diff --git a/rmw_zenoh_cpp/package.xml b/rmw_zenoh_cpp/package.xml index 3da4920d..3c8e1404 100644 --- a/rmw_zenoh_cpp/package.xml +++ b/rmw_zenoh_cpp/package.xml @@ -25,6 +25,7 @@ rosidl_typesupport_fastrtps_cpp rmw + ament_index_python ament_lint_auto ament_lint_common diff --git a/rmw_zenoh_cpp/test/rmw_zenoh_integration.test.py b/rmw_zenoh_cpp/test/rmw_zenoh_integration.test.py new file mode 100644 index 00000000..e7577160 --- /dev/null +++ b/rmw_zenoh_cpp/test/rmw_zenoh_integration.test.py @@ -0,0 +1,84 @@ +# Copyright 2024 Open Source Robotics Foundation, Inc. +# +# 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. + +import os +import sys +import signal +import subprocess +import time +import unittest + +import launch +import launch.actions +import launch.substitutions +import launch_ros.actions +import launch_testing.actions +import launch_testing.markers +import pytest + + +proc_env = os.environ.copy() +proc_env['RMW_IMPLEMENTATION'] = 'rmw_zenoh_cpp' + +@pytest.mark.launch_test +@launch_testing.markers.keep_alive +def generate_test_description(): + + selected_system_tests = launch.substitutions.LaunchConfiguration('selected_system_tests') + selected_system_tests_arg = launch.actions.DeclareLaunchArgument( + 'selected_system_tests', + default_value="test_rclcpp test_communication") + + zenoh_router = launch_ros.actions.Node( + package="rmw_zenoh_cpp", + executable="rmw_zenohd", + output="both", + env=proc_env + ) + + dut_process = launch.actions.ExecuteProcess( + cmd=[ + 'colcon', + 'test', + '--packages-select', + selected_system_tests, + '--retest-until-pass', + '2', + ], + shell=True, + env=proc_env, + ) + + return launch.LaunchDescription([ + selected_system_tests_arg, + zenoh_router, + dut_process, + # In tests where all of the procs under tests terminate themselves, it's necessary + # to add a dummy process not under test to keep the launch alive. launch_test + # provides a simple launch action that does this: + launch_testing.util.KeepAliveProc(), + launch_testing.actions.ReadyToTest() + ]) , {'dut_process': dut_process} + +class TestTerminatingProcessStops(unittest.TestCase): + def test_proc_terminates(self, proc_info, dut_process): + proc_info.assertWaitForShutdown(process=dut_process, timeout=400000) + +# These tests are run after the processes in generate_test_description() have shutdown. +@launch_testing.post_shutdown_test() +class TestShutdown(unittest.TestCase): + + def test_exit_codes(self, proc_info): + """Check if the processes exited normally.""" + launch_testing.asserts.assertExitCodes(proc_info)