1# Copyright (c) 2021-2024 Huawei Device Co., Ltd. 2# Licensed under the Apache License, Version 2.0 (the "License"); 3# you may not use this file except in compliance with the License. 4# You may obtain a copy of the License at 5# 6# http://www.apache.org/licenses/LICENSE-2.0 7# 8# Unless required by applicable law or agreed to in writing, software 9# distributed under the License is distributed on an "AS IS" BASIS, 10# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 11# See the License for the specific language governing permissions and 12# limitations under the License. 13# Convenience functions for testing Panda. 14 15include(${CMAKE_CURRENT_LIST_DIR}/PandaCmakeFunctions.cmake) 16 17function(common_add_gtest) 18 if(NOT PANDA_WITH_TESTS) 19 return() 20 endif() 21 22 set(prefix ARG) 23 set(noValues CONTAINS_MAIN NO_CORES RAPIDCHECK_ON NO_EXECUTABLE NO_WARNING_FILTER) 24 set(singleValues NAME OUTPUT_DIRECTORY TSAN_EXTRA_OPTIONS PANDA_STD_LIB ARK_BOOTCLASSPATH TEST_RUN_DIR TEST_GROUP STASH_LIST) 25 set(multiValues SOURCES INCLUDE_DIRS LIBRARIES SANITIZERS DEPS_TARGETS CUSTOM_PRERUN_ENVIRONMENT LAUNCHER) 26 set(TIMEOUT_SIGNAL USR1) 27 28 cmake_parse_arguments(${prefix} 29 "${noValues}" 30 "${singleValues}" 31 "${multiValues}" 32 ${ARGN}) 33 34 if (ARG_RAPIDCHECK_ON AND DEFINED DONT_USE_RAPIDCHECK) 35 return() 36 endif() 37 38 if (NOT DEFINED ARG_OUTPUT_DIRECTORY) 39 message(FATAL_ERROR "OUTPUT_DIRECTORY is not defined") 40 endif() 41 42 if (NOT ARG_CONTAINS_MAIN) 43 if (NOT CMAKE_CROSSCOMPILING) 44 set(ARG_SOURCES ${ARG_SOURCES} ${PANDA_ROOT}/tests/gtest_launcher/main.cpp) 45 endif() 46 endif() 47 48 if (ARG_RAPIDCHECK_ON) 49 if(NOT ARG_NO_EXECUTABLE) 50 panda_add_executable(${ARG_NAME} RAPIDCHECK_ON OUTPUT_DIRECTORY ${ARG_OUTPUT_DIRECTORY} EXCLUDE_FROM_ALL ${ARG_SOURCES}) 51 endif() 52 set_target_properties(${ARG_NAME} PROPERTIES LINK_FLAGS "-fno-rtti -fexceptions") 53 panda_target_compile_definitions(${ARG_NAME} PRIVATE PANDA_RAPIDCHECK) 54 panda_target_compile_options(${ARG_NAME} PRIVATE "-fno-rtti" "-fexceptions" "-fPIC") 55 panda_target_compile_definitions(${ARG_NAME} PUBLIC PANDA_RAPIDCHECK) 56 else() 57 if(NOT ARG_NO_EXECUTABLE) 58 panda_add_executable(${ARG_NAME} OUTPUT_DIRECTORY ${ARG_OUTPUT_DIRECTORY} EXCLUDE_FROM_ALL ${ARG_SOURCES}) 59 endif() 60 endif() 61 62 if(NOT ARG_NO_EXECUTABLE) 63 string(REPLACE "${PANDA_BINARY_ROOT}/" "" bin_path ${ARG_OUTPUT_DIRECTORY}) 64 if(NOT DEFINED ARG_STASH_LIST) 65 set(ARG_STASH_LIST stash_list) 66 endif() 67 set_property(GLOBAL APPEND PROPERTY ${ARG_STASH_LIST} "${bin_path}/${ARG_NAME}") 68 endif() 69 70 set(ARG_USE_GTESTS ON) 71 72 if (ARG_USE_GTESTS) 73 panda_target_compile_definitions(${ARG_NAME} PUBLIC PANDA_GTEST) 74 if (NOT ARG_CONTAINS_MAIN AND NOT CMAKE_CROSSCOMPILING) 75 find_program(GDB_PATH gdb REQUIRED) 76 panda_target_compile_definitions(${ARG_NAME} PUBLIC -DTIMEOUT_SIGNAL=SIG${TIMEOUT_SIGNAL} -DGDB_PATH=${GDB_PATH}) 77 endif() 78 endif() 79 80 if(PANDA_CI_TESTING_MODE STREQUAL "Nightly") 81 panda_target_compile_definitions(${ARG_NAME} PUBLIC PANDA_NIGHTLY_TEST_ON) 82 endif() 83 # By default tests are just built, running is available either via an 84 # umbrella target or via `ctest -R ...`. But one can always do something 85 # like this if really needed: 86 # add_custom_target(${ARG_NAME}_run 87 # COMMENT "Run ${ARG_NAME}" 88 # COMMAND ${CMAKE_CTEST_COMMAND} 89 # DEPENDS ${ARG_NAME}) 90 if (ARG_USE_GTESTS) 91 foreach(include_dir ${ARG_INCLUDE_DIRS}) 92 panda_target_include_directories(${ARG_NAME} PUBLIC ${include_dir}) 93 endforeach() 94 panda_target_include_directories(${ARG_NAME} SYSTEM PUBLIC 95 ${PANDA_THIRD_PARTY_SOURCES_DIR}/googletest/googlemock/include 96 ) 97 endif() 98 99 if (ARG_USE_GTESTS) 100 if (CONTAINS_MAIN OR NOT CMAKE_CROSSCOMPILING) 101 panda_target_link_libraries(${ARG_NAME} gtest) 102 else() 103 panda_target_link_libraries(${ARG_NAME} gtest_main) 104 endif() 105 endif() 106 107 if (NOT (PANDA_TARGET_MOBILE OR PANDA_TARGET_OHOS)) 108 panda_target_link_libraries(${ARG_NAME} pthread) 109 endif() 110 panda_target_link_libraries(${ARG_NAME} ${ARG_LIBRARIES}) 111 112 add_dependencies(gtests_build ${ARG_NAME} ${ARG_DEPS_TARGETS}) 113 114 if (ARG_RAPIDCHECK_ON) 115 panda_target_link_libraries(${ARG_NAME} rapidcheck) 116 panda_target_link_libraries(${ARG_NAME} rapidcheck_gtest) 117 panda_target_include_directories(${ARG_NAME} SYSTEM 118 PRIVATE ${PANDA_THIRD_PARTY_SOURCES_DIR}/rapidcheck/include 119 ) 120 add_dependencies(${ARG_NAME} rapidcheck_gtest) 121 add_dependencies(${ARG_NAME} rapidcheck) 122 endif() 123 124 panda_add_sanitizers(TARGET ${ARG_NAME} SANITIZERS ${ARG_SANITIZERS}) 125 126 set(prlimit_prefix "") 127 if (ARG_NO_CORES) 128 set(prlimit_prefix prlimit --core=0) 129 endif() 130 131 set(tsan_options "") 132 if ("thread" IN_LIST PANDA_SANITIZERS_LIST) 133 if (DEFINED ENV{TSAN_OPTIONS}) 134 set(tsan_options "TSAN_OPTIONS=$ENV{TSAN_OPTIONS},${ARG_TSAN_EXTRA_OPTIONS}") 135 endif() 136 endif() 137 138 # Yes, this is hardcoded. No, do not ask for an option. Go and fix your tests. 139 if (PANDA_CI_TESTING_MODE STREQUAL "Nightly") 140 set(timeout_prefix timeout --preserve-status --signal=${TIMEOUT_SIGNAL} --kill-after=30s 40m) 141 else () 142 set(timeout_prefix timeout --preserve-status --signal=${TIMEOUT_SIGNAL} --kill-after=30s 20m) 143 endif() 144 145 if (ARG_RAPIDCHECK_ON) 146 add_custom_target(${ARG_NAME}_rapidcheck_tests 147 COMMAND ${tsan_options} ${prlimit_prefix} ${timeout_prefix} 148 ${PANDA_RUN_PREFIX} "${ARG_OUTPUT_DIRECTORY}/${ARG_NAME}" 149 DEPENDS ${ARG_NAME} ${ARG_DEPS_TARGETS} 150 ) 151 add_dependencies(gtests ${ARG_NAME}_rapidcheck_tests) 152 else() 153 set(PANDA_STD_LIB "") 154 if (DEFINED ARG_PANDA_STD_LIB) 155 set(PANDA_STD_LIB "PANDA_STD_LIB=${ARG_PANDA_STD_LIB}") 156 endif() 157 158 set(ARK_BOOTCLASSPATH "") 159 if (DEFINED ARG_ARK_BOOTCLASSPATH) 160 set(ARK_BOOTCLASSPATH "ARK_BOOTCLASSPATH=${ARG_ARK_BOOTCLASSPATH}") 161 endif() 162 163 set(TEST_RUN_DIR ${CMAKE_CURRENT_BINARY_DIR}) 164 if(DEFINED ARG_TEST_RUN_DIR) 165 set(TEST_RUN_DIR ${ARG_TEST_RUN_DIR}) 166 endif() 167 168 if(NOT DEFINED ARG_LAUNCHER) 169 set(ARG_LAUNCHER "${ARG_OUTPUT_DIRECTORY}/${ARG_NAME}") 170 endif() 171 172 set(output_file "${ARG_OUTPUT_DIRECTORY}/${ARG_NAME}_gtest_output.txt") 173 174 # Some tests (examples: Logger.FileLogging) can work only with the "fast" mode. 175 # For such tests, it is necessary to disable filter using the NO_WARNING_FILTER flag. 176 # By default, the filter is enabled. 177 if(NOT ARG_NO_WARNING_FILTER) 178 set(FILTER ! grep "-q" 179 "'\\[WARNING] .* Death tests use fork(), which is unsafe particularly in a threaded context.'" 180 "${output_file}" 181 ) 182 else() 183 set(FILTER true) 184 endif() 185 set(PRINT_FILTER_TRIGGERING_MESSAGE 186 echo "Fail: using \\'fast\\' mode in multithreading test detected: please, check warnings below" 187 ) 188 189 add_custom_target(${ARG_NAME}_gtests 190 COMMAND ${PANDA_STD_LIB} ${ARK_BOOTCLASSPATH} ${ARG_CUSTOM_PRERUN_ENVIRONMENT} 191 ${tsan_options} ${prlimit_prefix} ${timeout_prefix} 192 ${PANDA_RUN_PREFIX} ${ARG_LAUNCHER} 193 --gtest_shuffle --gtest_death_test_style=threadsafe 194 --gtest_brief=0 195 >${output_file} 2>&1 196 && (${FILTER} || (${PRINT_FILTER_TRIGGERING_MESSAGE} && false)) 197 || (cat ${output_file} && false) 198 DEPENDS ${ARG_NAME} ${ARG_DEPS_TARGETS} 199 WORKING_DIRECTORY ${TEST_RUN_DIR} 200 ) 201 202 if(NOT DEFINED ARG_TEST_GROUP) 203 set(ARG_TEST_GROUP gtests) 204 endif() 205 add_dependencies(${ARG_TEST_GROUP} ${ARG_NAME}_gtests) 206 endif() 207endfunction() 208