From 4b5d89bcac346ab4e8d21eb3ba164822b3a0bc41 Mon Sep 17 00:00:00 2001 From: Tomoya Fujita <tomoya.fujita825@gmail.com> Date: Sun, 22 Dec 2024 13:35:16 -0800 Subject: [PATCH] add system test to github workflow for all distributions. (#32) * add system test to github workflow for all distributions. Signed-off-by: Tomoya.Fujita <tomoya.fujita825@gmail.com> * test yaml configuration path fix. Signed-off-by: Tomoya.Fujita <tomoya.fujita825@gmail.com> --------- Signed-off-by: Tomoya.Fujita <tomoya.fujita825@gmail.com> --- README.md | 5 ++-- scripts/build-verification.sh | 18 +++++++++++++- test/launch/test.launch.py | 7 ------ test/src/test.cpp | 13 +++++++--- test/test.py | 47 ++++++++++++++++++++++++++++------- 5 files changed, 67 insertions(+), 23 deletions(-) diff --git a/README.md b/README.md index 93c6712..2627d1c 100644 --- a/README.md +++ b/README.md @@ -162,7 +162,7 @@ to install local colcon workspace, # cd <colcon_workspace>/src # git clone https://github.com/fujitatomoya/ros2_persist_parameter_server # cd <colcon_workspace> -# colcon build --symlink-install +# colcon build --symlink-install --packages-select parameter_server ros2_persistent_parameter_server_test # source install/local_setup.bash ``` @@ -237,8 +237,7 @@ make sure to add the path of `launch` package to the PATH environment. ```bash # mkdir -p /tmp/test # cp <colcon_workspace>/src/ros2_persist_parameter/server/param/parameter_server.yaml /tmp/test -# cd <colcon_workspace>/src/ros2_persist_parameter/test -# ./test.py +# ./<colcon_workspace>/src/ros2_persist_parameter/test/test.py ``` All of the test is listed with result as following diff --git a/scripts/build-verification.sh b/scripts/build-verification.sh index 93ec38a..e731e04 100755 --- a/scripts/build-verification.sh +++ b/scripts/build-verification.sh @@ -49,10 +49,25 @@ function build_parameter_server () { echo "[${FUNCNAME[0]}]: build ROS 2 parameter server." source /opt/ros/${ROS_DISTRO}/setup.bash cd ${COLCON_WORKSPACE} - # TODO: test project should be integrated with `colcon test`. colcon build --symlink-install --packages-select parameter_server ros2_persistent_parameter_server_test } +function test_parameter_server () { + trap exit_trap ERR + echo "[${FUNCNAME[0]}]: test ROS 2 parameter server." + source /opt/ros/${ROS_DISTRO}/setup.bash + cd ${COLCON_WORKSPACE} + + # TODO(@fujitatomoya): currently unit tests are missing for parameter server with `colcon test`. + + # source the parameter server local packages + source ./install/local_setup.bash + # setup and execute the system test + mkdir /tmp/test + cp ./src/ros2_persist_parameter_server/server/param/parameter_server.yaml /tmp/test + ./src/ros2_persist_parameter_server/test/test.py +} + ######## # Main # ######## @@ -70,5 +85,6 @@ trap exit_trap ERR install_prerequisites setup_build_colcon_env build_parameter_server +test_parameter_server exit 0 diff --git a/test/launch/test.launch.py b/test/launch/test.launch.py index 6bc0cdf..403aca3 100644 --- a/test/launch/test.launch.py +++ b/test/launch/test.launch.py @@ -16,19 +16,12 @@ from launch import LaunchDescription from launch.substitutions import EnvironmentVariable -import launch_ros.actions import launch -import os -import sys -import pathlib def generate_launch_description(): return LaunchDescription([ launch.actions.ExecuteProcess( cmd = ['ros2', 'run', 'parameter_server', 'server', '--file-path', '/tmp/test/parameter_server.yaml'], respawn=True - ), - launch.actions.ExecuteProcess( - cmd = ['ros2', 'run', 'ros2_persistent_parameter_server_test', 'client'] ) ]) diff --git a/test/src/test.cpp b/test/src/test.cpp index 5aafa94..1bd6e50 100644 --- a/test/src/test.cpp +++ b/test/src/test.cpp @@ -118,17 +118,23 @@ class TestPersistParameter } // Get all test results. - inline void print_result() const + inline int print_result() const { + int ret = EXIT_SUCCESS; RCLCPP_INFO(this->get_logger(), "****************************************************" "***********************"); RCLCPP_INFO(this->get_logger(), "*********************************Test Result*********" "**********************"); for(const auto & res : result_map_) { RCLCPP_INFO(this->get_logger(), "%-60s : %16s", res.first.c_str(), res.second?"PASS":"NOT PASS"); + + // if any tests are not passed, return EXIT_FAILURE. + if (res.second == false) { + ret = EXIT_FAILURE; + } } - return; + return ret; } static inline rclcpp::Logger get_logger() @@ -223,7 +229,8 @@ int main(int argc, char ** argv) RCLCPP_ERROR(test_client->get_logger(), "unexpectedly failed: %s", e.what()); } - test_client->print_result(); + // if any tests are not passed, return EXIT_FAILURE. + ret_code = test_client->print_result(); rclcpp::shutdown(); return ret_code; diff --git a/test/test.py b/test/test.py index 0e09ac6..b45205f 100755 --- a/test/test.py +++ b/test/test.py @@ -1,17 +1,20 @@ #!/usr/bin/python3 -"""A script to start `Server && Client` throught launch file and responsible for killing the Server""" +"""A script to start `Server && Client` through launch file and responsible for killing the Server""" from threading import Thread -import time -import os -import sys -import signal -import shutil + +import os import psutil +import shutil +import signal +import subprocess +import sys +import time signal.signal(signal.SIGINT, signal.SIG_DFL) sleep_time = 3 -launchCmd = 'ros2 launch ros2_persistent_parameter_server_test test.launch.py' +launchServerCmd = ['ros2', 'launch', 'ros2_persistent_parameter_server_test', 'test.launch.py'] +launchClientCmd = ['ros2', 'run', 'ros2_persistent_parameter_server_test', 'client'] if shutil.which('ros2') is None: print("source <colcon_ws>/install/setup.bash...then retry.") @@ -33,8 +36,34 @@ def kill_server(): print("parameter server cannot be killed") return time.sleep(5) - print("Press CTRL-C to shutdown...") + #print("Press CTRL-C to shutdown...") + +# Start Server process with respawn enabled, this process stays running +server_process = subprocess.Popen(launchServerCmd, preexec_fn=os.setsid) +print(f"Parameter Server Process started with PID: {server_process.pid}") +# Start test client process +client_process = subprocess.Popen(launchClientCmd) +print(f"Parameter Client Process started with PID: {client_process.pid}") + +# Start killer thread to respawn the parameter server t = Thread(target = kill_server, args = ()) t.start() -os.system(launchCmd) + +# Wait until the client process finishes +return_code = client_process.wait() + +# Cleanup the process and thread +t.join() +os.killpg(os.getpgid(server_process.pid), signal.SIGTERM) + +print("\nTest process finished.") +print(f"Return Code: {return_code}") + +# Check if the client process completed successfully +if return_code == 0: + print("The process completed successfully.") + sys.exit(0) +else: + print("The process failed.") + sys.exit(1)