diff --git a/.cspell.json b/.cspell.json index 4c14cb9f3..83b4a3dc2 100644 --- a/.cspell.json +++ b/.cspell.json @@ -48,6 +48,7 @@ "stds", "struct", "structs", + "TOLOWER", "UDP_SEQ", "usec", "vccint", diff --git a/nebula_ros/CMakeLists.txt b/nebula_ros/CMakeLists.txt index 709de2025..b13cf4006 100644 --- a/nebula_ros/CMakeLists.txt +++ b/nebula_ros/CMakeLists.txt @@ -224,7 +224,19 @@ install(DIRECTORY include/ DESTINATION include/${PROJECT_NAME}) if(BUILD_TESTING) find_package(ament_lint_auto REQUIRED) + find_package(ros_testing REQUIRED) + ament_lint_auto_find_test_dependencies() + + foreach(MODEL Pandar40P Pandar64 PandarQT64 PandarQT128 Pandar128E4X PandarAT128 PandarXT32 PandarXT32M) + string(TOLOWER ${MODEL}_smoke_test test_name) + add_ros_test( + test/smoke_test.py + TARGET ${test_name} + ARGS "launch_file_path:=${PROJECT_SOURCE_DIR}/launch/nebula_launch.py" "sensor_model:=${MODEL}" + TIMEOUT "10" + ) + endforeach() endif() ament_export_include_directories("include/${PROJECT_NAME}") diff --git a/nebula_ros/package.xml b/nebula_ros/package.xml index 3a97db1f6..334a5f3da 100644 --- a/nebula_ros/package.xml +++ b/nebula_ros/package.xml @@ -11,6 +11,7 @@ ament_cmake_auto ros_environment + ros_testing continental_msgs continental_srvs @@ -34,6 +35,7 @@ ament_cmake_gtest ament_lint_auto + ros_testing ament_cmake diff --git a/nebula_ros/test/smoke_test.py b/nebula_ros/test/smoke_test.py new file mode 100644 index 000000000..7e6484723 --- /dev/null +++ b/nebula_ros/test/smoke_test.py @@ -0,0 +1,56 @@ +import time +import unittest + +from launch import LaunchContext +from launch import LaunchDescription +from launch.actions import IncludeLaunchDescription +from launch.actions import OpaqueFunction +from launch.launch_description_sources import PythonLaunchDescriptionSource +from launch.substitutions import LaunchConfiguration +import launch_testing +import launch_testing.actions +import launch_testing.asserts +import pytest +import rclpy + + +def resolve_launch_file(context: LaunchContext, *args, **kwargs): + sensor_model = LaunchConfiguration("sensor_model").perform(context) + launch_file_path = LaunchConfiguration("launch_file_path").perform(context) + + return [ + IncludeLaunchDescription( + PythonLaunchDescriptionSource(launch_file_path), + launch_arguments=[("sensor_model", sensor_model), ("launch_hw", "false")], + ) + ] + + +@pytest.mark.launch_test +def generate_test_description(): + return LaunchDescription( + [OpaqueFunction(function=resolve_launch_file), launch_testing.actions.ReadyToTest()] + ) + + +class DummyTest(unittest.TestCase): + def test_wait_for_node_ready(self): + """Waiting for the node is ready.""" + rclpy.init() + test_node = rclpy.create_node("test_node") + # Wait until both dummy node "test_node" and real tested node are registered and then kill + # both of them, if tested node does not register within `timeout` seconds test will fail + start_time = time.time() + timeout = 2 # seconds + timeout_msg = "Smoke test timeout has been reached ({}s)".format(timeout) + print("waiting for Nodes to be ready") + while len(test_node.get_node_names()) < 2: + assert time.time() - start_time < timeout, timeout_msg + time.sleep(0.1) + rclpy.shutdown() + + +@launch_testing.post_shutdown_test() +class TestYourNodeShutdown(unittest.TestCase): + def test_exit_code(self, proc_info): + launch_testing.asserts.assertExitCodes(proc_info) diff --git a/nebula_tests/package.xml b/nebula_tests/package.xml index f593b2e01..92d5456ee 100644 --- a/nebula_tests/package.xml +++ b/nebula_tests/package.xml @@ -15,6 +15,8 @@ diagnostic_updater nebula_common nebula_decoders + nebula_hw_interfaces + nebula_ros rosbag2_cpp ament_cmake_gtest