Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Add tests for user-defined signal handler #215

Merged
merged 4 commits into from
Aug 14, 2017
Merged
Show file tree
Hide file tree
Changes from 1 commit
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
56 changes: 51 additions & 5 deletions test_rclcpp/CMakeLists.txt
Original file line number Diff line number Diff line change
Expand Up @@ -73,7 +73,7 @@ if(BUILD_TESTING)
"rclcpp")
endfunction()

macro(custom_launch_test test_name executable1 executable2)
macro(custom_launch_test_two_executables test_name executable1 executable2)
set(TEST_NAME "${test_name}")
set(TEST_EXECUTABLE1 "$<TARGET_FILE:${executable1}>")
set(TEST_EXECUTABLE1_NAME "${executable1}")
Expand Down Expand Up @@ -101,6 +101,38 @@ if(BUILD_TESTING)
)
endmacro()

# Macro for tests that trigger the shutdown of an executable based on particular console output,
# then check the output of the executable against different console output.
macro(custom_launch_test_executable_output test_name executable)
set(TEST_NAME "${test_name}")
set(TEST_EXECUTABLE "$<TARGET_FILE:${executable}>")
set(TEST_EXECUTABLE_NAME "${executable}")
set(TEST_EXECUTABLE_TRIGGER_SHUTDOWN_OUTPUT
"${CMAKE_CURRENT_SOURCE_DIR}/test/${test_name}__trigger_shutdown")
set(TEST_EXECUTABLE_EXPECTED_OUTPUT
"${CMAKE_CURRENT_SOURCE_DIR}/test/${test_name}__expected_output")
configure_file(
test/test_executable_output.py.in
${test_name}${target_suffix}.py.configure
@ONLY
)
file(GENERATE
OUTPUT "${test_name}${target_suffix}_$<CONFIG>.py"
INPUT "${CMAKE_CURRENT_BINARY_DIR}/${test_name}${target_suffix}.py.configure"
)
ament_add_nose_test(${test_name}${target_suffix}
"${CMAKE_CURRENT_BINARY_DIR}/${test_name}${target_suffix}_$<CONFIG>.py"
${ARGN}
APPEND_LIBRARY_DIRS "${append_library_dirs}"
ENV
RCL_ASSERT_RMW_ID_MATCHES=${rmw_implementation}
RMW_IMPLEMENTATION=${rmw_implementation}
)
set_tests_properties(${test_name}${target_suffix}
PROPERTIES DEPENDS "${executable1}${target_suffix}"
Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

The variable executable1 doesn't seem to exist.

)
endmacro()

macro(targets)
custom_gtest(gtest_publisher
"test/test_publisher.cpp"
Expand Down Expand Up @@ -146,22 +178,34 @@ if(BUILD_TESTING)
TIMEOUT 30)

# Parameter tests single implementation
custom_launch_test(test_parameter_server_cpp
custom_launch_test_two_executables(test_parameter_server_cpp
test_parameters_server_cpp test_remote_parameters_cpp
TIMEOUT 15)

# Service tests single implementation
custom_launch_test(test_services_cpp
custom_launch_test_two_executables(test_services_cpp
test_services_server_cpp test_services_client_cpp
TIMEOUT 60)

custom_launch_test(test_client_scope_cpp
custom_launch_test_two_executables(test_client_scope_cpp
test_client_scope_server_cpp test_client_scope_client_cpp
TIMEOUT 30)

custom_launch_test(test_client_scope_consistency_cpp
custom_launch_test_two_executables(test_client_scope_consistency_cpp
test_client_scope_consistency_server_cpp test_client_scope_consistency_client_cpp
TIMEOUT 30)

# Test that a user-defined signal handler is called on interrupt:
# after rclcpp::init has been called, but before rclcpp::shutdown has been called.
custom_launch_test_executable_output(test_signal_handler_before_shutdown
test_signal_handler
TIMEOUT 30)

# Test that a user-defined signal handler is restored after rclcpp::init and rclcpp::shutdown
# have been called.
custom_launch_test_executable_output(test_signal_handler_after_shutdown
test_signal_handler
TIMEOUT 30)
endmacro()

set(append_library_dirs "${CMAKE_CURRENT_BINARY_DIR}")
Expand All @@ -171,6 +215,8 @@ if(BUILD_TESTING)

call_for_each_rmw_implementation(targets)

custom_executable(test_signal_handler "test/test_signal_handler.cpp")

# Parameter tests single implementation
custom_executable(test_parameters_server_cpp "test/test_parameters_server.cpp")
custom_executable(test_remote_parameters_cpp "test/test_remote_parameters.cpp")
Expand Down
1 change: 1 addition & 0 deletions test_rclcpp/package.xml
Original file line number Diff line number Diff line change
Expand Up @@ -17,6 +17,7 @@
<test_depend>ament_lint_auto</test_depend>
<test_depend>ament_lint_common</test_depend>
<test_depend>launch</test_depend>
<test_depend>launch_testing</test_depend>
<test_depend>rclcpp</test_depend>
<test_depend>rmw_implementation</test_depend>
<test_depend>rmw_implementation_cmake</test_depend>
Expand Down
51 changes: 51 additions & 0 deletions test_rclcpp/test/test_executable_output.py.in
Original file line number Diff line number Diff line change
@@ -0,0 +1,51 @@
# generated from test_rclcpp/test/test_two_executables.py.in
Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Copy-n-paste.


from launch import LaunchDescriptor
from launch.exit_handler import primary_exit_handler
from launch.launcher import DefaultLauncher
from launch.output_handler import ConsoleOutput

from launch_testing import create_handler


def @TEST_NAME@():
ld = LaunchDescriptor()

output_handlers = [ConsoleOutput()]

shutdown_trigger_handler = create_handler(
'@TEST_EXECUTABLE_NAME@',
ld,
'@TEST_EXECUTABLE_TRIGGER_SHUTDOWN_OUTPUT@',
exit_on_match=True,
filtered_rmw_implementation='@rmw_implementation@',
)
output_handlers.append(shutdown_trigger_handler)

output_check_handler = create_handler(
'@TEST_EXECUTABLE_NAME@',
ld,
'@TEST_EXECUTABLE_EXPECTED_OUTPUT@',
exit_on_match=False,
filtered_rmw_implementation='@rmw_implementation@',
)
output_handlers.append(output_check_handler)

ld.add_process(
cmd=['@TEST_EXECUTABLE@'],
name='@TEST_EXECUTABLE_NAME@',
exit_handler=primary_exit_handler,
output_handlers=output_handlers,
)

launcher = DefaultLauncher()
launcher.add_launch_descriptor(ld)
rc = launcher.launch()

assert rc == 0, "The launch file failed with exit code '" + str(rc) + "'. "

output_check_handler.check()


if __name__ == '__main__':
@TEST_NAME@()
54 changes: 54 additions & 0 deletions test_rclcpp/test/test_signal_handler.cpp
Original file line number Diff line number Diff line change
@@ -0,0 +1,54 @@
// Copyright 2017 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.

#include <iostream>
#include <memory>

#include "rclcpp/rclcpp.hpp"

using namespace std::chrono_literals;

void sigintHandler(int sig)
{
(void)sig;
printf("Custom sigint handler called.\n");
}

int main(int argc, char ** argv)
{
// This exectuable is used in combination with a script that interrupts it at different times.
// Its purpose is to test that a user-defined signal handler gets called even when the rclcpp
// signal handler is/has been in use.
setvbuf(stdout, NULL, _IONBF, BUFSIZ);

// Override default sigint handler
signal(SIGINT, sigintHandler);
printf("Registered custom signal handler.\n");

rclcpp::init(argc, argv);
printf("Called rclcpp::init.\n");

printf("Waiting to give an opportunity for interrupt...\n");
std::this_thread::sleep_for(5s);

printf("Calling rclcpp::shutdown...\n");
rclcpp::shutdown();
printf("Called rclcpp::shutdown.\n");

printf("Waiting to give an opportunity for interrupt...\n");
std::this_thread::sleep_for(5s);

printf("Exiting.\n");
return 0;
Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Couldn't this test be done without any output comparison? The signal handler could set a global variable which could be checked in the main function afterwards. I think that would simplify the test.

Copy link
Member Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Just checking the global variable you wouldn't know if the user-defined signal handler has been called "directly" or from within the rclcpp signal handler.
Checking for the presence/absence of the signal_handler(2) output from rclcpp we can infer this without any changes to rclcpp. If we think it's useful in other contexts, we can expose a flag from rclcpp and switch the test to check both variables. Otherwise, for the purpose of this test the console checking can provide that extra info.

}
Original file line number Diff line number Diff line change
@@ -0,0 +1,8 @@
Registered custom signal handler.
Called rclcpp::init.
Waiting to give an opportunity for interrupt...
Calling rclcpp::shutdown...
Called rclcpp::shutdown.
Waiting to give an opportunity for interrupt...
Custom sigint handler called.
Exiting.
Original file line number Diff line number Diff line change
@@ -0,0 +1,6 @@
Registered custom signal handler.
Called rclcpp::init.
Waiting to give an opportunity for interrupt...
Calling rclcpp::shutdown...
Called rclcpp::shutdown.
Waiting to give an opportunity for interrupt...
Original file line number Diff line number Diff line change
@@ -0,0 +1,9 @@
Registered custom signal handler.
Called rclcpp::init.
Waiting to give an opportunity for interrupt...
signal_handler(2)
Custom sigint handler called.
Calling rclcpp::shutdown...
Called rclcpp::shutdown.
Waiting to give an opportunity for interrupt...
Exiting.
Original file line number Diff line number Diff line change
@@ -0,0 +1,3 @@
Registered custom signal handler.
Called rclcpp::init.
Waiting to give an opportunity for interrupt...