From 690e2e453eed407725a4689bc84b0951c87973f3 Mon Sep 17 00:00:00 2001 From: Matthias Maier Date: Mon, 23 Jan 2023 20:40:58 -0600 Subject: [PATCH] CMake: add_test(): allow concurrent runs of tests with shared targets In order to make this possible we define an *additional* test (and test target) that depends on the executable target and ensures that the target is in place before it is called concurrently. --- cmake/macros/macro_deal_ii_add_test.cmake | 111 ++++++++++++++-------- 1 file changed, 72 insertions(+), 39 deletions(-) diff --git a/cmake/macros/macro_deal_ii_add_test.cmake b/cmake/macros/macro_deal_ii_add_test.cmake index 3cb92db2ad..b14cce2bc7 100644 --- a/cmake/macros/macro_deal_ii_add_test.cmake +++ b/cmake/macros/macro_deal_ii_add_test.cmake @@ -429,6 +429,15 @@ function(deal_ii_add_test _category _test_name _comparison_file) set(_shared_target FALSE) if(NOT "${_n_cpu}${_n_threads}" STREQUAL "00" OR "${_source_file}" MATCHES "(prm|json)$") set(_shared_target TRUE) + + # + # Build system-internal target name and final test name for the + # "executable" test. We have to make sure that the target and test + # names stay the same independent of test name and test category, + # thus the rather funny name: + # + set(_test_executable_target "test_dependency.${_target}.executable") + set(_test_executable_full "test_dependency/${_target}.executable") endif() # @@ -480,6 +489,35 @@ function(deal_ii_add_test _category _test_name _comparison_file) add_dependencies(compile_test_executables ${_target}) endif() + # + # Add a top level target to compile the test: + # + + if(_shared_target AND NOT TARGET ${_test_executable_target}) + add_custom_target(${_test_executable_target} + COMMAND echo "${_test_executable_full}: BUILD successful." + COMMAND echo "${_test_executable_full}: RUN skipped." + COMMAND echo "${_test_executable_full}: DIFF skipped." + COMMAND echo "${_test_executable_full}: PASSED." + DEPENDS ${_target} + ) + add_test(NAME ${_test_executable_full} + COMMAND ${CMAKE_COMMAND} + -DTRGT=${_test_executable_target} + -DTEST=${_test_executable_full} + -DEXPECT=PASSED + -DBINARY_DIR=${CMAKE_BINARY_DIR} + -DGUARD_FILE=${CMAKE_CURRENT_BINARY_DIR}/${_test_name}.${_build_lowercase}/interrupt_guard.cc + -P ${DEAL_II_PATH}/${DEAL_II_SHARE_RELDIR}/scripts/run_test.cmake + WORKING_DIRECTORY ${_test_directory} + ) + set_tests_properties(${_test_executable_full} PROPERTIES + LABEL "test_dependency" + TIMEOUT ${TEST_TIME_LIMIT} + FIXTURES_SETUP ${_test_executable_full} + ) + endif() + # # Add a top level target to run and compare the test: # @@ -548,20 +586,40 @@ function(deal_ii_add_test _category _test_name _comparison_file) # And finally define the test: # - add_test(NAME ${_test_full} - COMMAND ${CMAKE_COMMAND} - -DTRGT=${_test_target} - -DTEST=${_test_full} - -DEXPECT=${_expect} - -DBINARY_DIR=${CMAKE_BINARY_DIR} - -DGUARD_FILE=${CMAKE_CURRENT_BINARY_DIR}/${_test_name}.${_build_lowercase}/interrupt_guard.cc - -P ${DEAL_II_PATH}/${DEAL_II_SHARE_RELDIR}/scripts/run_test.cmake - WORKING_DIRECTORY ${_test_directory} - ) - set_tests_properties(${_test_full} PROPERTIES - LABEL "${_category}" - TIMEOUT ${TEST_TIME_LIMIT} - ) + if(_shared_target) + add_test(NAME ${_test_full} + COMMAND ${CMAKE_COMMAND} + -DTRGT=${_test_target} + -DTEST=${_test_full} + -DEXPECT=${_expect} + -DBINARY_DIR=${CMAKE_BINARY_DIR} + # no guard file + -P ${DEAL_II_PATH}/${DEAL_II_SHARE_RELDIR}/scripts/run_test.cmake + WORKING_DIRECTORY ${_test_directory} + ) + set_tests_properties(${_test_full} PROPERTIES + LABEL "${_category}" + TIMEOUT ${TEST_TIME_LIMIT} + FIXTURES_REQUIRED ${_test_executable_full} + ) + + else() + + add_test(NAME ${_test_full} + COMMAND ${CMAKE_COMMAND} + -DTRGT=${_test_target} + -DTEST=${_test_full} + -DEXPECT=${_expect} + -DBINARY_DIR=${CMAKE_BINARY_DIR} + -DGUARD_FILE=${CMAKE_CURRENT_BINARY_DIR}/${_test_name}.${_build_lowercase}/interrupt_guard.cc + -P ${DEAL_II_PATH}/${DEAL_II_SHARE_RELDIR}/scripts/run_test.cmake + WORKING_DIRECTORY ${_test_directory} + ) + set_tests_properties(${_test_full} PROPERTIES + LABEL "${_category}" + TIMEOUT ${TEST_TIME_LIMIT} + ) + endif() if(_exclusive) # @@ -599,31 +657,6 @@ function(deal_ii_add_test _category _test_name _comparison_file) endif() set_tests_properties(${_test_full} PROPERTIES PROCESSORS ${_slots}) endif() - - # - # Serialize all tests that share a common executable target. This - # involves tests with .threads=N. and .mpirun=N. annotation, as well - # as tests with parameter files (that might share a common executable - # target). - # - if(_shared_target) - # - # Running multiple variants of tests with the same target - # executable in parallel triggers a race condition where the same - # (not yet existent) target is built concurrently leading to - # undefined outcomes. - # - # Luckily CMake has a mechanism to force a test to be run after - # another has finished (and both are scheduled): - # - if(DEFINED TEST_DEPENDENCIES_${_target}) - set_tests_properties(${_test_full} PROPERTIES - DEPENDS ${TEST_DEPENDENCIES_${_target}} - ) - endif() - set(TEST_DEPENDENCIES_${_target} ${_test_full} PARENT_SCOPE) - endif() - endif() endforeach() endfunction() -- 2.39.5