@@ -15,6 +15,7 @@ include_guard(GLOBAL)
1515# Pack initialization into a function to avoid non-cache variable leakage.
1616function (_userver_prepare_testsuite )
1717 include ("${CMAKE_CURRENT_LIST_DIR } /UserverVenv.cmake" )
18+ include ("${CMAKE_CURRENT_LIST_DIR } /TargetIteration.cmake" )
1819 set_property (GLOBAL PROPERTY userver_cmake_dir "${CMAKE_CURRENT_LIST_DIR } " )
1920
2021 # @ingroup libraries
@@ -143,7 +144,7 @@ endfunction()
143144# TODO
144145function (userver_testsuite_add )
145146 set (oneValueArgs SERVICE_TARGET TEST_SUFFIX WORKING_DIRECTORY PYTHON_BINARY PRETTY_LOGS SQL_LIBRARY)
146- set (multiValueArgs PYTEST_ARGS REQUIREMENTS PYTHONPATH TEST_ENV)
147+ set (multiValueArgs PYTEST_ARGS REQUIREMENTS PYTHONPATH TEST_ENV RESOURCE_LOCKS )
147148 cmake_parse_arguments (ARG "${options} " "${oneValueArgs} " "${multiValueArgs} " ${ARGN} )
148149
149150 _userver_setup_environment_validate_impl ()
@@ -207,7 +208,8 @@ function(userver_testsuite_add)
207208 set (TESTSUITE_RUNNER "${CMAKE_CURRENT_BINARY_DIR } /runtests-${service_target_with_suffix} " )
208209 list (APPEND ARG_PYTHONPATH "${USERVER_TESTSUITE_DIR} /pytest_plugins" )
209210
210- file (MAKE_DIRECTORY ${CMAKE_CURRENT_BINARY_DIR } /Testing/Temporary )
211+ set (testsuite_temp_dir "${CMAKE_CURRENT_BINARY_DIR } /Testing/Temporary/${service_target_with_suffix} " )
212+ file (MAKE_DIRECTORY "${testsuite_temp_dir} " )
211213
212214 set (TESTS_PATHS ${ARG_WORKING_DIRECTORY} )
213215 if (ARG_SQL_LIBRARY)
@@ -224,8 +226,8 @@ function(userver_testsuite_add)
224226 "${python_binary} " "${USERVER_TESTSUITE_DIR} /create_runner.py" "--output=${TESTSUITE_RUNNER} "
225227 "--python=${python_binary} " "--tests-path=${TESTS_PATHS} " "--working-dir=${CMAKE_CURRENT_BINARY_DIR } "
226228 "--python-path=${ARG_PYTHONPATH} " -- "--build-dir=${CMAKE_CURRENT_BINARY_DIR } "
227- "--service-logs-file=${CMAKE_CURRENT_BINARY_DIR } /Testing/Temporary /service.log"
228- "--basetemp=${CMAKE_CURRENT_BINARY_DIR } /Testing/Temporary " ${ARG_PYTEST_ARGS}
229+ "--service-logs-file=${testsuite_temp_dir} /service.log"
230+ "--basetemp=${testsuite_temp_dir} " ${ARG_PYTEST_ARGS}
229231 DEPENDS "${USERVER_TESTSUITE_DIR} /create_runner.py"
230232 COMMENT "Creating testsuite runner at ${TESTSUITE_RUNNER} "
231233 VERBATIM ${CODEGEN}
@@ -253,6 +255,13 @@ function(userver_testsuite_add)
253255 set_tests_properties ("${testsuite_test_name} " PROPERTIES ENVIRONMENT "${ARG_TEST_ENV} " )
254256 endif ()
255257
258+ _userver_get_test_resource_locks_for_target ("${ARG_SERVICE_TARGET} " testsuite_resource_locks )
259+ list (APPEND testsuite_resource_locks ${ARG_RESOURCE_LOCKS} )
260+ if (testsuite_resource_locks)
261+ list (REMOVE_DUPLICATES testsuite_resource_locks)
262+ set_tests_properties ("${testsuite_test_name} " PROPERTIES RESOURCE_LOCK "${testsuite_resource_locks} " )
263+ endif ()
264+
256265 # Pre-collect command in a list to support spaces in paths
257266 set (testsuite_start_command)
258267 list (APPEND testsuite_start_command "${python_binary} " )
@@ -293,6 +302,8 @@ endfunction()
293302# @multiparam REQUIREMENTS
294303# @multiparam PYTHONPATH
295304# @multiparam TEST_ENV
305+ # @multiparam RESOURCE_LOCKS ctest resource locks for databases the service uses
306+ # without linking their module (e.g. 'userver_postgresql' for an odbc service)
296307function (userver_testsuite_add_simple )
297308 set (oneValueArgs
298309 SERVICE_TARGET
@@ -307,7 +318,7 @@ function(userver_testsuite_add_simple)
307318 DUMP_CONFIG
308319 SQL_LIBRARY
309320 )
310- set (multiValueArgs PYTEST_ARGS REQUIREMENTS PYTHONPATH TEST_ENV)
321+ set (multiValueArgs PYTEST_ARGS REQUIREMENTS PYTHONPATH TEST_ENV RESOURCE_LOCKS )
311322 cmake_parse_arguments (ARG "${options} " "${oneValueArgs} " "${multiValueArgs} " ${ARGN} )
312323
313324 _userver_setup_environment_validate_impl ()
@@ -455,6 +466,7 @@ function(userver_testsuite_add_simple)
455466 REQUIREMENTS ${ARG_REQUIREMENTS}
456467 PYTHONPATH ${ARG_PYTHONPATH}
457468 TEST_ENV ${ARG_TEST_ENV}
469+ RESOURCE_LOCKS ${ARG_RESOURCE_LOCKS}
458470 SQL_LIBRARY ${ARG_SQL_LIBRARY}
459471 )
460472endfunction ()
@@ -495,6 +507,14 @@ function(userver_add_utest)
495507 if (ARG_TEST_ENV)
496508 set_tests_properties ("${ARG_NAME} " PROPERTIES ENVIRONMENT "${ARG_TEST_ENV} " )
497509 endif ()
510+
511+ set (utest_resource_locks "" )
512+ foreach (database IN LISTS ARG_DATABASES)
513+ list (APPEND utest_resource_locks "userver_${database} " )
514+ endforeach ()
515+ if (utest_resource_locks)
516+ set_tests_properties ("${ARG_NAME} " PROPERTIES RESOURCE_LOCK "${utest_resource_locks} " )
517+ endif ()
498518endfunction ()
499519
500520# @param NAME
@@ -528,4 +548,41 @@ function(userver_add_ubench_test)
528548 )
529549endfunction ()
530550
551+ # Converts a target name into a ';'-separated list of ctest RESOURCE_LOCK names, one
552+ # per userver database module the target links against (directly or transitively).
553+ # Tests that share a lock are never run concurrently by ctest, which protects the
554+ # per-engine database daemons started by testsuite (each on a fixed port/data-dir)
555+ # from races during parallel `ctest -j`. Lock name for an engine is "userver_<engine>".
556+ function (_userver_get_test_resource_locks_for_target target output_var )
557+ # userver database modules backed by a shared daemon. Embedded engines without a
558+ # daemon (e.g. sqlite, rocks) are intentionally omitted.
559+ set (db_engines
560+ postgresql
561+ mongo
562+ redis
563+ clickhouse
564+ rabbitmq
565+ kafka
566+ mysql
567+ ydb
568+ )
569+
570+ set (resource_locks "" )
571+ if (TARGET "${target} " )
572+ _userver_collect_linked_targets ("${target} " linked_targets )
573+ foreach (engine IN LISTS db_engines)
574+ list (FIND linked_targets "userver-${engine} " index_dash)
575+ list (FIND linked_targets "userver::${engine} " index_colons)
576+ if (NOT index_dash EQUAL -1 OR NOT index_colons EQUAL -1)
577+ list (APPEND resource_locks "userver_${engine} " )
578+ endif ()
579+ endforeach ()
580+ endif ()
581+
582+ set (${output_var}
583+ "${resource_locks} "
584+ PARENT_SCOPE
585+ )
586+ endfunction ()
587+
531588_userver_prepare_testsuite ()
0 commit comments