]> https://gitweb.dealii.org/ - dealii.git/commitdiff
CMake: add_test(): allow concurrent runs of tests with shared targets
authorMatthias Maier <tamiko@43-1.org>
Tue, 24 Jan 2023 02:40:58 +0000 (20:40 -0600)
committerMatthias Maier <tamiko@43-1.org>
Wed, 25 Jan 2023 23:26:29 +0000 (17:26 -0600)
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

index 3cb92db2ada180b396345cad79c9dd1142578517..b14cce2bc77d2c1db91aa6fbe4ffbf588b5bfea3 100644 (file)
@@ -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()

In the beginning the Universe was created. This has made a lot of people very angry and has been widely regarded as a bad move.

Douglas Adams


Typeset in Trocchi and Trocchi Bold Sans Serif.