diff options
author | Brad King <brad.king@kitware.com> | 2023-05-11 17:32:15 (GMT) |
---|---|---|
committer | Brad King <brad.king@kitware.com> | 2023-06-02 10:51:13 (GMT) |
commit | 54c5654f7d530ea363b3fcc02f2176d79342c07b (patch) | |
tree | 23a2bd337eb22e827914dbbb9d631899bd78dd8e /Tests/RunCMake | |
parent | e38c05688ed637bdda8e6af5f2d76fc12bee35e3 (diff) | |
download | CMake-54c5654f7d530ea363b3fcc02f2176d79342c07b.zip CMake-54c5654f7d530ea363b3fcc02f2176d79342c07b.tar.gz CMake-54c5654f7d530ea363b3fcc02f2176d79342c07b.tar.bz2 |
ctest: Optionally terminate tests with a custom signal on timeout
CTest normally terminates test processes on timeout using `SIGKILL`.
Offer tests a chance to exit gracefully, on platforms supporting POSIX
signals, by setting `TIMEOUT_SIGNAL_{NAME,GRACE_PERIOD}` properties.
Fixes: #17288
Diffstat (limited to 'Tests/RunCMake')
22 files changed, 241 insertions, 1 deletions
diff --git a/Tests/RunCMake/CTestCommandLine/RunCMakeTest.cmake b/Tests/RunCMake/CTestCommandLine/RunCMakeTest.cmake index bda260a..c90d543 100644 --- a/Tests/RunCMake/CTestCommandLine/RunCMakeTest.cmake +++ b/Tests/RunCMake/CTestCommandLine/RunCMakeTest.cmake @@ -479,3 +479,32 @@ set_tests_properties(test5 PROPERTIES SKIP_REGULAR_EXPRESSION \"please skip\") run_cmake_command(output-junit ${CMAKE_CTEST_COMMAND} --output-junit "${RunCMake_TEST_BINARY_DIR}/junit.xml") endfunction() run_output_junit() + +if(WIN32) + block() + set(RunCMake_TEST_BINARY_DIR ${RunCMake_BINARY_DIR}/TimeoutSignalWindows) + set(RunCMake_TEST_NO_CLEAN 1) + file(REMOVE_RECURSE "${RunCMake_TEST_BINARY_DIR}") + file(MAKE_DIRECTORY "${RunCMake_TEST_BINARY_DIR}") + file(WRITE "${RunCMake_TEST_BINARY_DIR}/CTestTestfile.cmake" " +add_test(test1 \"${CMAKE_COMMAND}\" -E true) +set_tests_properties(test1 PROPERTIES TIMEOUT_SIGNAL_NAME SIGUSR1) +set_tests_properties(test1 PROPERTIES TIMEOUT_SIGNAL_GRACE_PERIOD 1) +") + run_cmake_command(TimeoutSignalWindows ${CMAKE_CTEST_COMMAND}) + endblock() +else() + block() + set(RunCMake_TEST_BINARY_DIR ${RunCMake_BINARY_DIR}/TimeoutSignalBad) + set(RunCMake_TEST_NO_CLEAN 1) + file(REMOVE_RECURSE "${RunCMake_TEST_BINARY_DIR}") + file(MAKE_DIRECTORY "${RunCMake_TEST_BINARY_DIR}") + file(WRITE "${RunCMake_TEST_BINARY_DIR}/CTestTestfile.cmake" " +add_test(test1 \"${CMAKE_COMMAND}\" -E true) +set_tests_properties(test1 PROPERTIES TIMEOUT_SIGNAL_NAME NOTASIG) +set_tests_properties(test1 PROPERTIES TIMEOUT_SIGNAL_GRACE_PERIOD 0) +set_tests_properties(test1 PROPERTIES TIMEOUT_SIGNAL_GRACE_PERIOD 1000) +") + run_cmake_command(TimeoutSignalBad ${CMAKE_CTEST_COMMAND}) + endblock() +endif() diff --git a/Tests/RunCMake/CTestCommandLine/TimeoutSignalBad-result.txt b/Tests/RunCMake/CTestCommandLine/TimeoutSignalBad-result.txt new file mode 100644 index 0000000..d197c91 --- /dev/null +++ b/Tests/RunCMake/CTestCommandLine/TimeoutSignalBad-result.txt @@ -0,0 +1 @@ +[^0] diff --git a/Tests/RunCMake/CTestCommandLine/TimeoutSignalBad-stderr.txt b/Tests/RunCMake/CTestCommandLine/TimeoutSignalBad-stderr.txt new file mode 100644 index 0000000..ba4235d --- /dev/null +++ b/Tests/RunCMake/CTestCommandLine/TimeoutSignalBad-stderr.txt @@ -0,0 +1 @@ +Errors while running CTest diff --git a/Tests/RunCMake/CTestCommandLine/TimeoutSignalBad-stdout.txt b/Tests/RunCMake/CTestCommandLine/TimeoutSignalBad-stdout.txt new file mode 100644 index 0000000..e848dcf --- /dev/null +++ b/Tests/RunCMake/CTestCommandLine/TimeoutSignalBad-stdout.txt @@ -0,0 +1,5 @@ + Start 1: test1 +TIMEOUT_SIGNAL_NAME "NOTASIG" not supported on this platform\. +TIMEOUT_SIGNAL_GRACE_PERIOD "0" is not greater than "0" seconds\. +TIMEOUT_SIGNAL_GRACE_PERIOD "1000" is not less than the maximum of "60" seconds\. +1/1 Test #1: test1 ............................\*\*\*Not Run +[0-9.]+ sec diff --git a/Tests/RunCMake/CTestCommandLine/TimeoutSignalWindows-result.txt b/Tests/RunCMake/CTestCommandLine/TimeoutSignalWindows-result.txt new file mode 100644 index 0000000..d197c91 --- /dev/null +++ b/Tests/RunCMake/CTestCommandLine/TimeoutSignalWindows-result.txt @@ -0,0 +1 @@ +[^0] diff --git a/Tests/RunCMake/CTestCommandLine/TimeoutSignalWindows-stderr.txt b/Tests/RunCMake/CTestCommandLine/TimeoutSignalWindows-stderr.txt new file mode 100644 index 0000000..ba4235d --- /dev/null +++ b/Tests/RunCMake/CTestCommandLine/TimeoutSignalWindows-stderr.txt @@ -0,0 +1 @@ +Errors while running CTest diff --git a/Tests/RunCMake/CTestCommandLine/TimeoutSignalWindows-stdout.txt b/Tests/RunCMake/CTestCommandLine/TimeoutSignalWindows-stdout.txt new file mode 100644 index 0000000..295ace5 --- /dev/null +++ b/Tests/RunCMake/CTestCommandLine/TimeoutSignalWindows-stdout.txt @@ -0,0 +1,4 @@ + Start 1: test1 +TIMEOUT_SIGNAL_NAME is not supported on Windows\. +TIMEOUT_SIGNAL_GRACE_PERIOD is not supported on Windows\. +1/1 Test #1: test1 ............................\*\*\*Not Run +[0-9.]+ sec diff --git a/Tests/RunCMake/CTestTimeout/CMakeLists.txt.in b/Tests/RunCMake/CTestTimeout/CMakeLists.txt.in index ee3323c..1045d1a 100644 --- a/Tests/RunCMake/CTestTimeout/CMakeLists.txt.in +++ b/Tests/RunCMake/CTestTimeout/CMakeLists.txt.in @@ -2,6 +2,10 @@ cmake_minimum_required(VERSION 3.16) project(CTestTest@CASE_NAME@ C) include(CTest) +if(CMAKE_C_COMPILER_ID STREQUAL "SunPro" AND CMAKE_C_COMPILER_VERSION VERSION_LESS 5.14) + set(CMAKE_C_STANDARD 99) +endif() + add_executable(TestTimeout TestTimeout.c) if(NOT DEFINED TIMEOUT) diff --git a/Tests/RunCMake/CTestTimeout/RunCMakeTest.cmake b/Tests/RunCMake/CTestTimeout/RunCMakeTest.cmake index a4080e3..6caeef1 100644 --- a/Tests/RunCMake/CTestTimeout/RunCMakeTest.cmake +++ b/Tests/RunCMake/CTestTimeout/RunCMakeTest.cmake @@ -13,12 +13,68 @@ endfunction() run_ctest_timeout(Basic) -if(UNIX) +if(WIN32) + string(CONCAT CASE_CMAKELISTS_SUFFIX_CODE [[ + set_tests_properties(TestTimeout PROPERTIES + TIMEOUT_SIGNAL_NAME SIGUSR1 + TIMEOUT_SIGNAL_GRACE_PERIOD 1.2 + ) +]]) + run_ctest_timeout(SignalWindows) + unset(CASE_CMAKELISTS_SUFFIX_CODE) + +else() string(CONCAT CASE_CMAKELISTS_SUFFIX_CODE [[ target_compile_definitions(TestTimeout PRIVATE FORK) ]]) run_ctest_timeout(Fork) unset(CASE_CMAKELISTS_SUFFIX_CODE) + + string(CONCAT CASE_CMAKELISTS_SUFFIX_CODE [[ + target_compile_definitions(TestTimeout PRIVATE SIGNAL) + set_tests_properties(TestTimeout PROPERTIES + TIMEOUT_SIGNAL_NAME SIGUSR1 + TIMEOUT_SIGNAL_GRACE_PERIOD 1.2 + ) +]]) + run_ctest_timeout(Signal) + unset(CASE_CMAKELISTS_SUFFIX_CODE) + + string(CONCAT CASE_CMAKELISTS_SUFFIX_CODE [[ + target_compile_definitions(TestTimeout PRIVATE SIGNAL SIGNAL_IGNORE=1) + set_tests_properties(TestTimeout PROPERTIES + TIMEOUT_SIGNAL_NAME SIGUSR1 + # Use default TIMEOUT_SIGNAL_GRACE_PERIOD of 1. + ) +]]) + run_ctest_timeout(SignalIgnore) + unset(CASE_CMAKELISTS_SUFFIX_CODE) + + string(CONCAT CASE_CMAKELISTS_SUFFIX_CODE [[ + set_tests_properties(TestTimeout PROPERTIES + TIMEOUT_SIGNAL_NAME NOTASIG + ) +]]) + run_ctest_timeout(SignalUnknown) + unset(CASE_CMAKELISTS_SUFFIX_CODE) + + string(CONCAT CASE_CMAKELISTS_SUFFIX_CODE [[ + set_tests_properties(TestTimeout PROPERTIES + TIMEOUT_SIGNAL_NAME SIGUSR1 + TIMEOUT_SIGNAL_GRACE_PERIOD -1 + ) +]]) + run_ctest_timeout(SignalGraceLow) + unset(CASE_CMAKELISTS_SUFFIX_CODE) + + string(CONCAT CASE_CMAKELISTS_SUFFIX_CODE [[ + set_tests_properties(TestTimeout PROPERTIES + TIMEOUT_SIGNAL_NAME SIGUSR1 + TIMEOUT_SIGNAL_GRACE_PERIOD 1000 + ) +]]) + run_ctest_timeout(SignalGraceHigh) + unset(CASE_CMAKELISTS_SUFFIX_CODE) endif() block() diff --git a/Tests/RunCMake/CTestTimeout/Signal-check.cmake b/Tests/RunCMake/CTestTimeout/Signal-check.cmake new file mode 100644 index 0000000..bee5ac7 --- /dev/null +++ b/Tests/RunCMake/CTestTimeout/Signal-check.cmake @@ -0,0 +1,11 @@ +file(GLOB test_xml "${RunCMake_TEST_BINARY_DIR}/Testing/*/Test.xml") +if(NOT test_xml) + set(RunCMake_TEST_FAILED "Test.xml not found.") + return() +endif() + +file(READ "${test_xml}" test_xml_content) +if(NOT test_xml_content MATCHES "SIGUSR1") + set(RunCMake_TEST_FAILED "Test output does not mention SIGUSR1.") + return() +endif() diff --git a/Tests/RunCMake/CTestTimeout/Signal-stdout.txt b/Tests/RunCMake/CTestTimeout/Signal-stdout.txt new file mode 100644 index 0000000..6cb5d0c --- /dev/null +++ b/Tests/RunCMake/CTestTimeout/Signal-stdout.txt @@ -0,0 +1,6 @@ +Test project [^ +]*/Tests/RunCMake/CTestTimeout/Signal-build + Start 1: TestTimeout +1/1 Test #1: TestTimeout ......................\*\*\*Timeout \(SIGUSR1\) +[1-9][0-9.]* sec ++ +0% tests passed, 1 tests failed out of 1 diff --git a/Tests/RunCMake/CTestTimeout/SignalGraceHigh-check.cmake b/Tests/RunCMake/CTestTimeout/SignalGraceHigh-check.cmake new file mode 100644 index 0000000..96dabc8 --- /dev/null +++ b/Tests/RunCMake/CTestTimeout/SignalGraceHigh-check.cmake @@ -0,0 +1,11 @@ +file(GLOB test_xml "${RunCMake_TEST_BINARY_DIR}/Testing/*/Test.xml") +if(NOT test_xml) + set(RunCMake_TEST_FAILED "Test.xml not found.") + return() +endif() + +file(READ "${test_xml}" test_xml_content) +if(NOT test_xml_content MATCHES "TIMEOUT_SIGNAL_GRACE_PERIOD \"1000\" is not less than the maximum of \"60\" seconds\\.") + set(RunCMake_TEST_FAILED "Test output does not have expected error message.") + return() +endif() diff --git a/Tests/RunCMake/CTestTimeout/SignalGraceHigh-stdout.txt b/Tests/RunCMake/CTestTimeout/SignalGraceHigh-stdout.txt new file mode 100644 index 0000000..fc965c0 --- /dev/null +++ b/Tests/RunCMake/CTestTimeout/SignalGraceHigh-stdout.txt @@ -0,0 +1,3 @@ + Start 1: TestTimeout +TIMEOUT_SIGNAL_GRACE_PERIOD "1000" is not less than the maximum of "60" seconds\. +1/1 Test #1: TestTimeout ......................\*\*\*Not Run +[0-9.]+ sec diff --git a/Tests/RunCMake/CTestTimeout/SignalGraceLow-check.cmake b/Tests/RunCMake/CTestTimeout/SignalGraceLow-check.cmake new file mode 100644 index 0000000..c4b01e5 --- /dev/null +++ b/Tests/RunCMake/CTestTimeout/SignalGraceLow-check.cmake @@ -0,0 +1,11 @@ +file(GLOB test_xml "${RunCMake_TEST_BINARY_DIR}/Testing/*/Test.xml") +if(NOT test_xml) + set(RunCMake_TEST_FAILED "Test.xml not found.") + return() +endif() + +file(READ "${test_xml}" test_xml_content) +if(NOT test_xml_content MATCHES "TIMEOUT_SIGNAL_GRACE_PERIOD \"-1\" is not greater than \"0\" seconds\\.") + set(RunCMake_TEST_FAILED "Test output does not have expected error message.") + return() +endif() diff --git a/Tests/RunCMake/CTestTimeout/SignalGraceLow-stdout.txt b/Tests/RunCMake/CTestTimeout/SignalGraceLow-stdout.txt new file mode 100644 index 0000000..097cab6 --- /dev/null +++ b/Tests/RunCMake/CTestTimeout/SignalGraceLow-stdout.txt @@ -0,0 +1,3 @@ + Start 1: TestTimeout +TIMEOUT_SIGNAL_GRACE_PERIOD "-1" is not greater than "0" seconds. +1/1 Test #1: TestTimeout ......................\*\*\*Not Run +[0-9.]+ sec diff --git a/Tests/RunCMake/CTestTimeout/SignalIgnore-check.cmake b/Tests/RunCMake/CTestTimeout/SignalIgnore-check.cmake new file mode 100644 index 0000000..e408764 --- /dev/null +++ b/Tests/RunCMake/CTestTimeout/SignalIgnore-check.cmake @@ -0,0 +1,11 @@ +file(GLOB test_xml "${RunCMake_TEST_BINARY_DIR}/Testing/*/Test.xml") +if(NOT test_xml) + set(RunCMake_TEST_FAILED "Test.xml not found.") + return() +endif() + +file(READ "${test_xml}" test_xml_content) +if(NOT test_xml_content MATCHES "EINTR") + set(RunCMake_TEST_FAILED "Test output does not mention EINTR.") + return() +endif() diff --git a/Tests/RunCMake/CTestTimeout/SignalIgnore-stdout.txt b/Tests/RunCMake/CTestTimeout/SignalIgnore-stdout.txt new file mode 100644 index 0000000..de97df4 --- /dev/null +++ b/Tests/RunCMake/CTestTimeout/SignalIgnore-stdout.txt @@ -0,0 +1,6 @@ +Test project [^ +]*/Tests/RunCMake/CTestTimeout/SignalIgnore-build + Start 1: TestTimeout +1/1 Test #1: TestTimeout ......................\*\*\*Timeout +[1-9][0-9.]* sec ++ +0% tests passed, 1 tests failed out of 1 diff --git a/Tests/RunCMake/CTestTimeout/SignalUnknown-check.cmake b/Tests/RunCMake/CTestTimeout/SignalUnknown-check.cmake new file mode 100644 index 0000000..d024934 --- /dev/null +++ b/Tests/RunCMake/CTestTimeout/SignalUnknown-check.cmake @@ -0,0 +1,11 @@ +file(GLOB test_xml "${RunCMake_TEST_BINARY_DIR}/Testing/*/Test.xml") +if(NOT test_xml) + set(RunCMake_TEST_FAILED "Test.xml not found.") + return() +endif() + +file(READ "${test_xml}" test_xml_content) +if(NOT test_xml_content MATCHES "TIMEOUT_SIGNAL_NAME \"NOTASIG\" not supported on this platform\\.") + set(RunCMake_TEST_FAILED "Test output does not have expected error message.") + return() +endif() diff --git a/Tests/RunCMake/CTestTimeout/SignalUnknown-stdout.txt b/Tests/RunCMake/CTestTimeout/SignalUnknown-stdout.txt new file mode 100644 index 0000000..33a133f --- /dev/null +++ b/Tests/RunCMake/CTestTimeout/SignalUnknown-stdout.txt @@ -0,0 +1,3 @@ + Start 1: TestTimeout +TIMEOUT_SIGNAL_NAME "NOTASIG" not supported on this platform\. +1/1 Test #1: TestTimeout ......................\*\*\*Not Run +[0-9.]+ sec diff --git a/Tests/RunCMake/CTestTimeout/SignalWindows-check.cmake b/Tests/RunCMake/CTestTimeout/SignalWindows-check.cmake new file mode 100644 index 0000000..1bf7f8a --- /dev/null +++ b/Tests/RunCMake/CTestTimeout/SignalWindows-check.cmake @@ -0,0 +1,11 @@ +file(GLOB test_xml "${RunCMake_TEST_BINARY_DIR}/Testing/*/Test.xml") +if(NOT test_xml) + set(RunCMake_TEST_FAILED "Test.xml not found.") + return() +endif() + +file(READ "${test_xml}" test_xml_content) +if(NOT test_xml_content MATCHES "TIMEOUT_SIGNAL_NAME is not supported on Windows\\.") + set(RunCMake_TEST_FAILED "Test output does not have expected error message.") + return() +endif() diff --git a/Tests/RunCMake/CTestTimeout/SignalWindows-stdout.txt b/Tests/RunCMake/CTestTimeout/SignalWindows-stdout.txt new file mode 100644 index 0000000..6911015 --- /dev/null +++ b/Tests/RunCMake/CTestTimeout/SignalWindows-stdout.txt @@ -0,0 +1,4 @@ + Start 1: TestTimeout +TIMEOUT_SIGNAL_GRACE_PERIOD is not supported on Windows\. +TIMEOUT_SIGNAL_NAME is not supported on Windows\. +1/1 Test #1: TestTimeout ......................\*\*\*Not Run +[0-9.]+ sec diff --git a/Tests/RunCMake/CTestTimeout/TestTimeout.c b/Tests/RunCMake/CTestTimeout/TestTimeout.c index 0d534fc..425548c 100644 --- a/Tests/RunCMake/CTestTimeout/TestTimeout.c +++ b/Tests/RunCMake/CTestTimeout/TestTimeout.c @@ -1,3 +1,8 @@ +#if !defined(_WIN32) && !defined(__APPLE__) && !defined(__OpenBSD__) +/* NOLINTNEXTLINE(bugprone-reserved-identifier) */ +# define _XOPEN_SOURCE 600 +#endif + #if defined(_WIN32) # include <windows.h> #else @@ -7,6 +12,19 @@ #include <stdio.h> +#ifdef SIGNAL +# include <errno.h> +# include <signal.h> +# include <string.h> + +static unsigned int signal_count; +static void signal_handler(int signum) +{ + (void)signum; + ++signal_count; +} +#endif + int main(void) { #ifdef FORK @@ -16,10 +34,39 @@ int main(void) } #endif +#ifdef SIGNAL + struct sigaction sa; + memset(&sa, 0, sizeof(sa)); + sa.sa_handler = signal_handler; + while ((sigaction(SIGUSR1, &sa, NULL) < 0) && (errno == EINTR)) + ; +#endif + #if defined(_WIN32) Sleep((TIMEOUT + 4) * 1000); +#elif defined(SIGNAL_IGNORE) +# if defined(__CYGWIN__) || defined(__sun__) +# define ERRNO_IS_EINTR (errno == EINTR || errno == 0) +# else +# define ERRNO_IS_EINTR (errno == EINTR) +# endif + { + unsigned int timeLeft = (TIMEOUT + 4 + SIGNAL_IGNORE); + while ((timeLeft = sleep(timeLeft), timeLeft > 0 && ERRNO_IS_EINTR)) { + printf("EINTR: timeLeft=%u\n", timeLeft); + fflush(stdout); + } + } #else sleep((TIMEOUT + 4)); #endif + +#ifdef SIGNAL + if (signal_count > 0) { + printf("SIGUSR1: count=%u\n", signal_count); + fflush(stdout); + } +#endif + return 0; } |