LYTestWrappers.cmake 28 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438439440441442443444445446447448449450451452453454455456457458459460461462463464465466467468469470471472473474475476477478479480481482483484485486487488489490491492493494495496497498499500501502503504505506507508509510511512513514515516517518519520521522523524525526527528529530531532533534535536537538539540
  1. #
  2. # Copyright (c) Contributors to the Open 3D Engine Project.
  3. # For complete copyright and license terms please see the LICENSE at the root of this distribution.
  4. #
  5. # SPDX-License-Identifier: Apache-2.0 OR MIT
  6. #
  7. #
  8. include_guard()
  9. # LY_GOOGLETEST_EXTRA_PARAMS to append additional
  10. # google test parameters to every google test invocation.
  11. set(LY_GOOGLETEST_EXTRA_PARAMS CACHE STRING "Allows injection of additional options to be passed to all google test commands")
  12. # Note pytest does not need the above because it natively has PYTEST_ADDOPTS environment
  13. # variable support.
  14. find_package(Python REQUIRED MODULE)
  15. ly_set(LY_PYTEST_EXECUTABLE ${LY_PYTHON_CMD} -B -m pytest -v --tb=short --show-capture=stdout -c ${LY_ROOT_FOLDER}/pytest.ini --build-directory "${CMAKE_RUNTIME_OUTPUT_DIRECTORY}/$<CONFIG>")
  16. ly_set(LY_TEST_GLOBAL_KNOWN_SUITE_NAMES "smoke" "main" "periodic" "benchmark" "sandbox" "awsi")
  17. ly_set(LY_TEST_GLOBAL_KNOWN_REQUIREMENTS "gpu")
  18. # Set default test aborts to 25 minutes, avoids hitting the CI pipeline inactivity timeout usually set to 30 minutes
  19. ly_set(LY_TEST_DEFAULT_TIMEOUT 1500)
  20. # Add the CMake Test targets for each suite if testing is supported
  21. if(PAL_TRAIT_BUILD_TESTS_SUPPORTED)
  22. ly_add_suite_build_and_run_targets(${LY_TEST_GLOBAL_KNOWN_SUITE_NAMES})
  23. endif()
  24. # Set and create folders for PyTest and GTest xml output
  25. ly_set(PYTEST_XML_OUTPUT_DIR ${CMAKE_BINARY_DIR}/Testing/Pytest)
  26. ly_set(GTEST_XML_OUTPUT_DIR ${CMAKE_BINARY_DIR}/Testing/Gtest)
  27. ly_set(LYTESTTOOLS_OUTPUT_DIR ${CMAKE_BINARY_DIR}/Testing/LyTestTools)
  28. file(MAKE_DIRECTORY ${PYTEST_XML_OUTPUT_DIR})
  29. file(MAKE_DIRECTORY ${GTEST_XML_OUTPUT_DIR})
  30. #! ly_check_valid_test_suites: internal helper to check for errors in test suites
  31. function(ly_check_valid_test_suite suite_name)
  32. if(NOT ${suite_name} IN_LIST LY_TEST_GLOBAL_KNOWN_SUITE_NAMES)
  33. message(SEND_ERROR "Invalid test suite name ${suite_name} in ${CMAKE_CURRENT_LIST_FILE}, it can only be one of the following: ${LY_TEST_GLOBAL_KNOWN_SUITE_NAMES} or unspecified.")
  34. endif()
  35. endfunction()
  36. #! ly_check_valid_test_requires: internal helper to check for errors in test requirements
  37. function(ly_check_valid_test_requires)
  38. foreach(name_check ${ARGV})
  39. if(NOT ${name_check} IN_LIST LY_TEST_GLOBAL_KNOWN_REQUIREMENTS)
  40. message(SEND_ERROR "Invalid test requirement name ${name_check} in ${CMAKE_CURRENT_LIST_FILE}, it can only be one of the following: ${LY_TEST_GLOBAL_KNOWN_REQUIREMENTS} or unspecified")
  41. endif()
  42. endforeach()
  43. endfunction()
  44. #! ly_strip_target_namespace: Strips all "::" namespaces from target
  45. # \arg: TARGET - Target to remove namespace prefixes
  46. # \arg: OUTPUT_VARIABLE - Variable which will be set to output containing the stripped target
  47. function(ly_strip_target_namespace)
  48. set(one_value_args TARGET OUTPUT_VARIABLE)
  49. cmake_parse_arguments(ly_strip_target_namespace "${options}" "${one_value_args}" "${multi_value_args}" ${ARGN})
  50. if(NOT ly_strip_target_namespace_OUTPUT_VARIABLE)
  51. message(SEND_ERROR "Output variable must be supplied to ${CMAKE_CURRENT_FUNCTION}")
  52. endif()
  53. string(REPLACE "::" ";" qualified_name_list ${ly_strip_target_namespace_TARGET})
  54. list(POP_BACK qualified_name_list stripped_target)
  55. set(${ly_strip_target_namespace_OUTPUT_VARIABLE} ${stripped_target} PARENT_SCOPE)
  56. endfunction()
  57. #! ly_add_test: Adds a new RUN_TEST for the specified target using the supplied command
  58. #
  59. # \arg:NAME - Name of the test run target
  60. # \arg:PARENT_NAME(optional) - Name of the parent test run target (if this is a subsequent call to specify a suite)
  61. # \arg:TEST_REQUIRES(optional) - List of system resources that are required to run this test.
  62. # Only available option is "gpu"
  63. # \arg:TEST_SUITE(optional) - "smoke" or "periodic" or "benchmark" or "sandbox" or "awsi" - prevents the test from running normally
  64. # and instead places it in a special suite of tests that only run when requested.
  65. # Otherwise, do not specify a TEST_SUITE value and the default ("main") will apply.
  66. # "smoke" is tiny, quick tests of fundamental operation (tests with no suite marker will also execute here in CI)
  67. # "periodic" is low-priority verification, which should not block code submission
  68. # "benchmark" is currently reserved for Google Benchmarks
  69. # "sandbox" should be only be used for the workflow of flaky tests
  70. # "awsi" Time consuming AWS integration end-to-end tests
  71. # \arg:TIMEOUT (optional) The timeout in seconds for the module. Defaults to LY_TEST_DEFAULT_TIMEOUT.
  72. # \arg:TEST_COMMAND - Command which runs the tests. It is a required argument
  73. # \arg:NON_IDE_PARAMS - extra params that will be run in ctest, but will not be used in the IDE.
  74. # This exists because there is only one IDE "target" (dll or executable)
  75. # but many potential tests which invoke it with different filters (suites).
  76. # Those params which vary per CTest are stored in this parameter
  77. # and do not appy to the "launch options" for the IDE target.
  78. # \arg:RUNTIME_DEPENDENCIES (optional) - List of additional runtime dependencies required by this test.
  79. # \arg:COMPONENT (optional) - Scope of the feature area that the test belongs to (eg. physics, graphics, etc.).
  80. # \arg:LABELS (optional) - Additional labels to apply to the test target which can be used by ctest filters.
  81. # \arg:EXCLUDE_TEST_RUN_TARGET_FROM_IDE(bool) - If set the test run target will be not be shown in the IDE
  82. # \arg:TEST_LIBRARY(internal) - Internal variable that contains the library be used. This is only to be used by the other
  83. # ly_add_* function below, not by user code
  84. # sets LY_ADDED_TEST_NAME to the fully qualified name of the test, in parent scope
  85. function(ly_add_test)
  86. if(NOT PAL_TRAIT_BUILD_TESTS_SUPPORTED)
  87. return()
  88. endif()
  89. set(options EXCLUDE_TEST_RUN_TARGET_FROM_IDE)
  90. set(one_value_args NAME PARENT_NAME TEST_LIBRARY TEST_SUITE TIMEOUT)
  91. set(multi_value_args TEST_REQUIRES TEST_COMMAND NON_IDE_PARAMS RUNTIME_DEPENDENCIES COMPONENT LABELS)
  92. # note that we dont use TEST_LIBRARY here, but PAL files might so do not remove!
  93. cmake_parse_arguments(ly_add_test "${options}" "${one_value_args}" "${multi_value_args}" ${ARGN})
  94. if (ly_add_test_UNPARSED_ARGUMENTS)
  95. message(SEND_ERROR "Invalid arguments passed to ly_add_test: ${ly_add_test_UNPARSED_ARGUMENTS}")
  96. endif()
  97. if(NOT ly_add_test_NAME)
  98. message(FATAL_ERROR "You must provide a name for the target")
  99. endif()
  100. if(NOT ly_add_test_TEST_SUITE)
  101. set(ly_add_test_TEST_SUITE "main")
  102. endif()
  103. # Set default test module timeout
  104. if(NOT ly_add_test_TIMEOUT)
  105. set(ly_add_test_TIMEOUT ${LY_TEST_DEFAULT_TIMEOUT})
  106. elseif(ly_add_test_TIMEOUT GREATER LY_TEST_DEFAULT_TIMEOUT)
  107. message(FATAL_ERROR "TIMEOUT for test ${ly_add_test_NAME} set at ${ly_add_test_TIMEOUT} seconds which is longer than the default of ${LY_TEST_DEFAULT_TIMEOUT}. Allowing a single module to run exceedingly long creates problems in a CI pipeline.")
  108. endif()
  109. if(NOT ly_add_test_TEST_COMMAND)
  110. message(FATAL_ERROR "TEST_COMMAND arguments must be supplied in order to run test")
  111. endif()
  112. # Treat supplied TEST_COMMAND argument as a list. The first element is used as the test command
  113. list(POP_FRONT ly_add_test_TEST_COMMAND test_command)
  114. # The remaining elements are treated as arguments to the command
  115. set(test_arguments ${ly_add_test_TEST_COMMAND})
  116. # Check that the supplied test suites and test requires are from the choices we provide
  117. ly_check_valid_test_requires(${ly_add_test_TEST_REQUIRES})
  118. ly_check_valid_test_suite(${ly_add_test_TEST_SUITE})
  119. set(qualified_test_run_name_with_suite "${ly_add_test_NAME}.${ly_add_test_TEST_SUITE}")
  120. # Retrieves platform specific arguments that is used for adding arguments to the test
  121. set(PAL_TEST_COMMAND_ARGS)
  122. set(wrapper_file ${CMAKE_CURRENT_FUNCTION_LIST_DIR}/Platform/${PAL_PLATFORM_NAME}/LYTestWrappers_${PAL_PLATFORM_NAME_LOWERCASE}.cmake)
  123. if(NOT EXISTS ${wrapper_file})
  124. o3de_pal_dir(wrapper_file ${wrapper_file} "${O3DE_ENGINE_RESTRICTED_PATH}" "${LY_ROOT_FOLDER}")
  125. endif()
  126. include(${wrapper_file})
  127. add_test(
  128. NAME ${qualified_test_run_name_with_suite}::TEST_RUN
  129. COMMAND ${test_command} ${test_arguments} ${ly_add_test_NON_IDE_PARAMS} ${PAL_TEST_COMMAND_ARGS}
  130. )
  131. set(LY_ADDED_TEST_NAME ${qualified_test_run_name_with_suite}::TEST_RUN)
  132. set(LY_ADDED_TEST_NAME ${LY_ADDED_TEST_NAME} PARENT_SCOPE)
  133. set(final_labels SUITE_${ly_add_test_TEST_SUITE})
  134. if (ly_add_test_TEST_REQUIRES)
  135. list(TRANSFORM ly_add_test_TEST_REQUIRES PREPEND "REQUIRES_" OUTPUT_VARIABLE prepended_list)
  136. list(APPEND final_labels ${prepended_list})
  137. # Workaround so we can filter "AND" of labels until https://gitlab.kitware.com/cmake/cmake/-/issues/21087 is fixed
  138. list(TRANSFORM prepended_list PREPEND "SUITE_${ly_add_test_TEST_SUITE}_" OUTPUT_VARIABLE prepended_list)
  139. list(APPEND final_labels ${prepended_list})
  140. endif()
  141. if (ly_add_test_COMPONENT)
  142. list(TRANSFORM ly_add_test_COMPONENT PREPEND "COMPONENT_" OUTPUT_VARIABLE prepended_component_list)
  143. list(APPEND final_labels ${prepended_component_list})
  144. endif()
  145. if (ly_add_test_LABELS)
  146. list(APPEND final_labels ${ly_add_test_LABELS})
  147. endif()
  148. # Allow TIAF to apply the label of supported test categories from being run by CTest
  149. o3de_test_impact_apply_test_labels(${ly_add_test_TEST_LIBRARY} final_labels)
  150. # labels expects a single param, of concatenated labels
  151. # this always has a value because ly_add_test_TEST_SUITE is automatically
  152. # filled in to be "main" if not specified.
  153. set_tests_properties(${LY_ADDED_TEST_NAME}
  154. PROPERTIES
  155. LABELS "${final_labels}"
  156. TIMEOUT ${ly_add_test_TIMEOUT}
  157. )
  158. # ly_add_test_NAME could be an alias, we need the actual un-aliased target
  159. set(unaliased_test_name ${ly_add_test_NAME})
  160. if(TARGET ${ly_add_test_NAME})
  161. get_target_property(alias ${ly_add_test_NAME} ALIASED_TARGET)
  162. if(alias)
  163. set(unaliased_test_name ${alias})
  164. endif()
  165. endif()
  166. if(NOT ly_add_test_EXCLUDE_TEST_RUN_TARGET_FROM_IDE AND NOT PAL_TRAIT_BUILD_EXCLUDE_ALL_TEST_RUNS_FROM_IDE)
  167. list(JOIN test_arguments " " test_arguments_line)
  168. if(TARGET ${unaliased_test_name})
  169. # In this case we already have a target, we inject the debugging parameters for the target directly
  170. set_target_properties(${unaliased_test_name} PROPERTIES
  171. VS_DEBUGGER_COMMAND ${test_command}
  172. VS_DEBUGGER_COMMAND_ARGUMENTS "${test_arguments_line}"
  173. )
  174. else()
  175. # Adds a custom target for the test run
  176. # The true command is used to add a target-level dependency on the test command
  177. ly_strip_target_namespace(TARGET ${unaliased_test_name} OUTPUT_VARIABLE unaliased_test_name)
  178. add_custom_target(${unaliased_test_name} COMMAND ${CMAKE_COMMAND} -E true ${args_TEST_COMMAND} ${args_TEST_ARGUMENTS})
  179. file(RELATIVE_PATH project_path ${LY_ROOT_FOLDER} ${CMAKE_CURRENT_SOURCE_DIR})
  180. set(ide_path ${project_path})
  181. # Visual Studio doesn't support a folder layout that starts with ".."
  182. # So strip away the parent directory of a relative path
  183. if (${project_path} MATCHES [[^(\.\./)+(.*)]])
  184. set(ide_path "${CMAKE_MATCH_2}")
  185. endif()
  186. set_target_properties(${unaliased_test_name} PROPERTIES
  187. FOLDER "${ide_path}"
  188. VS_DEBUGGER_COMMAND ${test_command}
  189. VS_DEBUGGER_COMMAND_ARGUMENTS "${test_arguments_line}"
  190. )
  191. # In the case where we are creating a custom target, we need to add dependency to the target
  192. if(ly_add_test_PARENT_NAME AND NOT ${ly_add_test_NAME} STREQUAL ${ly_add_test_PARENT_NAME})
  193. ly_add_dependencies(${unaliased_test_name} ${ly_add_test_PARENT_NAME})
  194. endif()
  195. endif()
  196. # For test projects that are custom targets, pass a props file that sets the project as "Console" so
  197. # it leaves the console open when it finishes
  198. set_target_properties(${unaliased_test_name} PROPERTIES VS_USER_PROPS "${LY_ROOT_FOLDER}/cmake/Platform/Common/MSVC/TestProject.props")
  199. # Include additional dependencies
  200. if (ly_add_test_RUNTIME_DEPENDENCIES)
  201. ly_add_dependencies(${unaliased_test_name} ${ly_add_test_RUNTIME_DEPENDENCIES})
  202. endif()
  203. # RUN_TESTS wont build dependencies: https://gitlab.kitware.com/cmake/cmake/issues/8774
  204. # In the mean time we add a custom target and mark the dependency
  205. ly_add_dependencies(TEST_SUITE_${ly_add_test_TEST_SUITE} ${unaliased_test_name})
  206. else()
  207. # Include additional dependencies
  208. if (ly_add_test_RUNTIME_DEPENDENCIES)
  209. ly_add_dependencies(TEST_SUITE_${ly_add_test_TEST_SUITE} ${ly_add_test_RUNTIME_DEPENDENCIES})
  210. endif()
  211. # Include additional tests
  212. if (TARGET ${unaliased_test_name})
  213. ly_add_dependencies(TEST_SUITE_${ly_add_test_TEST_SUITE} ${unaliased_test_name})
  214. endif()
  215. endif()
  216. if(NOT ly_add_test_PARENT_NAME)
  217. set(test_target ${ly_add_test_NAME})
  218. else()
  219. set(test_target ${ly_add_test_PARENT_NAME})
  220. endif()
  221. # Check to see whether or not this test target has been stored in the global list for walking by the test impact analysis framework
  222. get_property(all_tests GLOBAL PROPERTY LY_ALL_TESTS)
  223. if(NOT "${test_target}" IN_LIST all_tests)
  224. # Extract the test target name from the namespace::target_name composite
  225. string(REGEX REPLACE ".*::" "" test_name "${test_target}")
  226. # Store the test target name sans namespace so they can be looked up without the preceeding namespace
  227. set_property(GLOBAL APPEND PROPERTY O3DE_ALL_TESTS_DE_NAMESPACED ${test_name})
  228. # This is the first reference to this test target so add it to the global list
  229. set_property(GLOBAL APPEND PROPERTY LY_ALL_TESTS ${test_target})
  230. set_property(GLOBAL PROPERTY LY_ALL_TESTS_${test_target}_TEST_LIBRARY ${ly_add_test_TEST_LIBRARY})
  231. endif()
  232. # Add the test suite, timeout value and labels to the test target params
  233. set(LY_TEST_PARAMS "${LY_TEST_PARAMS}#${ly_add_test_TEST_SUITE}")
  234. set(LY_TEST_PARAMS "${LY_TEST_PARAMS}#${ly_add_test_TIMEOUT}")
  235. string(REPLACE ";" "," flattened_labels "${final_labels}")
  236. set(LY_TEST_PARAMS "${LY_TEST_PARAMS}#${flattened_labels}")
  237. # Store the params and labels for this test target
  238. set_property(GLOBAL APPEND PROPERTY LY_ALL_TESTS_${test_target}_PARAMS ${LY_TEST_PARAMS})
  239. endfunction()
  240. #! ly_add_pytest: registers target PyTest-based test with CTest
  241. #
  242. # \arg:NAME name of the test-module to register with CTest
  243. # \arg:PATH path to the file (or dir) containing pytest-based tests
  244. # \arg:PYTEST_MARKS (optional) extra pytest marker filtering string (see pytest arg "-m")
  245. # \arg:EXTRA_ARGS (optional) additional arguments to pass to PyTest, should not include pytest marks (value for "-m" should be passed to PYTEST_MARKS)
  246. # \arg:TEST_SERIAL (bool) disable parallel execution alongside other test modules, important when this test depends on shared resources or environment state
  247. # \arg:TEST_REQUIRES (optional) list of system resources needed by the tests in this module. Used to filter out execution when those system resources are not available. For example, 'gpu'
  248. # \arg:RUNTIME_DEPENDENCIES (optional) - List of additional runtime dependencies required by this test.
  249. # \arg:COMPONENT (optional) - Scope of the feature area that the test belongs to (eg. physics, graphics, etc.).
  250. # \arg:EXCLUDE_TEST_RUN_TARGET_FROM_IDE(bool) - If set the test run target will be not be shown in the IDE
  251. # \arg:TEST_SUITE(optional) - "smoke" or "periodic" or "sandbox" or "awsi" - prevents the test from running normally
  252. # and instead places it a special suite of tests that only run when requested.
  253. # \arg:TIMEOUT (optional) The timeout in seconds for the module. If not set defaults to LY_TEST_DEFAULT_TIMEOUT
  254. #
  255. function(ly_add_pytest)
  256. if(NOT PAL_TRAIT_TEST_PYTEST_SUPPORTED OR NOT PAL_TRAIT_TEST_LYTESTTOOLS_SUPPORTED)
  257. return()
  258. endif()
  259. set(options TEST_SERIAL)
  260. set(oneValueArgs NAME PATH TEST_SUITE PYTEST_MARKS)
  261. set(multiValueArgs EXTRA_ARGS COMPONENT)
  262. cmake_parse_arguments(ly_add_pytest "${options}" "${oneValueArgs}" "${multiValueArgs}" ${ARGN})
  263. if(NOT ly_add_pytest_PATH)
  264. message(FATAL_ERROR "Must supply a value for PATH to tests")
  265. endif()
  266. if(ly_add_pytest_PYTEST_MARKS)
  267. # Suite marker args added by non_ide_params will duplicate those set by custom_marks_args
  268. # however resetting flags is safe and overrides with the final value set
  269. set(custom_marks_args "-m" "${ly_add_pytest_PYTEST_MARKS}")
  270. endif()
  271. string(REPLACE "::" "_" pytest_report_directory "${PYTEST_XML_OUTPUT_DIR}/${ly_add_pytest_NAME}.xml")
  272. string(REPLACE "::" "_" pytest_output_directory "${LYTESTTOOLS_OUTPUT_DIR}/${ly_add_pytest_NAME}")
  273. # Add the script path to the test target params
  274. set(LY_TEST_PARAMS "${ly_add_pytest_PATH}")
  275. # Command to run the test
  276. set(test_command ${LY_PYTEST_EXECUTABLE} ${ly_add_pytest_PATH} ${ly_add_pytest_EXTRA_ARGS} --output-path ${pytest_output_directory} --junitxml=${pytest_report_directory} ${custom_marks_args})
  277. ly_add_test(
  278. NAME ${ly_add_pytest_NAME}
  279. PARENT_NAME ${ly_add_pytest_NAME}
  280. TEST_SUITE ${ly_add_pytest_TEST_SUITE}
  281. LABELS FRAMEWORK_pytest
  282. TEST_COMMAND ${test_command}
  283. TEST_LIBRARY pytest
  284. COMPONENT ${ly_add_pytest_COMPONENT}
  285. ${ly_add_pytest_UNPARSED_ARGUMENTS}
  286. )
  287. set_property(GLOBAL APPEND PROPERTY LY_ALL_TESTS_${ly_add_pytest_NAME}_SCRIPT_PATH ${ly_add_pytest_PATH})
  288. set_property(GLOBAL APPEND PROPERTY LY_ALL_TESTS_${ly_add_pytest_NAME}_TEST_COMMAND ${test_command})
  289. set_tests_properties(${LY_ADDED_TEST_NAME} PROPERTIES RUN_SERIAL "${ly_add_pytest_TEST_SERIAL}")
  290. endfunction()
  291. #! ly_add_googletest: Adds a new RUN_TEST using for the specified target using the supplied command or fallback to running
  292. # googletest tests through AzTestRunner
  293. # \arg:NAME Name to for the test run target
  294. # \arg:TARGET Name of the target module that is being run for tests. If not provided, will default to 'NAME'
  295. # \arg:TEST_REQUIRES(optional) List of system resources that are required to run this test.
  296. # Only available option is "gpu"
  297. # \arg:TEST_SUITE(optional) - "smoke" or "periodic" or "sandbox" or "awsi" - prevents the test from running normally
  298. # and instead places it a special suite of tests that only run when requested.
  299. # \arg:TEST_COMMAND(optional) - Command which runs the tests.
  300. # If not supplied, a default of "AzTestRunner $<TARGET_FILE:${NAME}> AzRunUnitTests" will be used
  301. # \arg:COMPONENT (optional) - Scope of the feature area that the test belongs to (eg. physics, graphics, etc.).
  302. # \arg:TIMEOUT (optional) The timeout in seconds for the module. If not set, will have its timeout set by ly_add_test to the default timeout.
  303. # \arg:EXCLUDE_TEST_RUN_TARGET_FROM_IDE(bool) - If set the test run target will be not be shown in the IDE
  304. function(ly_add_googletest)
  305. if(NOT PAL_TRAIT_BUILD_TESTS_SUPPORTED)
  306. message(FATAL_ERROR "Platform does not support test targets")
  307. endif()
  308. set(one_value_args NAME TARGET TEST_SUITE)
  309. set(multi_value_args TEST_COMMAND COMPONENT)
  310. cmake_parse_arguments(ly_add_googletest "${options}" "${one_value_args}" "${multi_value_args}" ${ARGN})
  311. if (ly_add_googletest_TARGET)
  312. set(target_name ${ly_add_googletest_TARGET})
  313. else()
  314. set(target_name ${ly_add_googletest_NAME})
  315. endif()
  316. # AzTestRunner modules only supports google test libraries, regardless of whether or not
  317. # google test suites are supported
  318. set_property(GLOBAL APPEND PROPERTY LY_AZTESTRUNNER_TEST_MODULES "${target_name}")
  319. if(NOT PAL_TRAIT_TEST_GOOGLE_TEST_SUPPORTED)
  320. return()
  321. endif()
  322. if (ly_add_googletest_TEST_SUITE AND NOT ly_add_googletest_TEST_SUITE STREQUAL "main")
  323. # if a suite is specified, we filter to only accept things which match that suite (in c++)
  324. set(non_ide_params "--gtest_filter=*SUITE_${ly_add_googletest_TEST_SUITE}*")
  325. else()
  326. # otherwise, if its the main suite we only runs things that dont have any of the other suites.
  327. # Note: it doesn't do AND, only 'or' - so specifying SUITE_main:REQUIRES_gpu
  328. # will actually run everything in main OR everything tagged as requiring a GPU
  329. # instead of only tests tagged with BOTH main and gpu...
  330. # so we have to do it this way (negating all others)
  331. set(non_ide_params "--gtest_filter=-*SUITE_smoke*:*SUITE_periodic*:*SUITE_benchmark*:*SUITE_sandbox*:*SUITE_awsi*")
  332. endif()
  333. if(NOT ly_add_googletest_TEST_COMMAND)
  334. # Use the NAME parameter as the build target
  335. set(build_target ${target_name})
  336. ly_strip_target_namespace(TARGET ${build_target} OUTPUT_VARIABLE build_target)
  337. if(NOT TARGET ${build_target})
  338. message(FATAL_ERROR "A valid build target \"${build_target}\" for test run \"${target_name}\" has not been found.\
  339. A valid target via the TARGET parameter or a custom TEST_COMMAND must be supplied")
  340. endif()
  341. # If command is not supplied attempts, uses the AzTestRunner to run googletest on the supplied NAME
  342. set(full_test_command $<TARGET_FILE:AZ::AzTestRunner> $<TARGET_FILE:${build_target}> AzRunUnitTests)
  343. # Add AzTestRunner as a build dependency
  344. ly_add_dependencies(${build_target} AZ::AzTestRunner)
  345. # Start the test target params and dd the command runner command
  346. # Ideally, we would populate the full command procedurally but the generator expressions won't be expanded by the time we need this data
  347. set(LY_TEST_PARAMS "AzRunUnitTests")
  348. else()
  349. set(full_test_command ${ly_add_googletest_TEST_COMMAND})
  350. # Remove the generator expressions so we are left with the argument(s) required to run unit tests for executable targets
  351. string(REPLACE ";" "" stripped_test_command ${full_test_command})
  352. string(GENEX_STRIP ${stripped_test_command} stripped_test_command)
  353. # Start the test target params and dd the command runner command
  354. set(LY_TEST_PARAMS "${stripped_test_command}")
  355. endif()
  356. string(REPLACE "::" "_" report_directory "${GTEST_XML_OUTPUT_DIR}/${ly_add_googletest_NAME}.xml")
  357. # Invoke the lower level ly_add_test command to add the actual ctest and setup the test labels to add_dependencies on the target
  358. ly_add_test(
  359. NAME ${ly_add_googletest_NAME}
  360. PARENT_NAME ${target_name}
  361. TEST_SUITE ${ly_add_googletest_TEST_SUITE}
  362. LABELS FRAMEWORK_googletest
  363. TEST_COMMAND ${full_test_command} --gtest_output=xml:${report_directory} ${LY_GOOGLETEST_EXTRA_PARAMS}
  364. TEST_LIBRARY googletest
  365. ${ly_add_googletest_UNPARSED_ARGUMENTS}
  366. NON_IDE_PARAMS ${non_ide_params}
  367. RUNTIME_DEPENDENCIES AZ::AzTestRunner
  368. COMPONENT ${ly_add_googletest_COMPONENT}
  369. )
  370. endfunction()
  371. #! ly_add_googlebenchmark: Adds a new RUN_TEST using for the specified target using the supplied command or fallback to running
  372. # benchmark tests through AzTestRunner
  373. # \arg:NAME Name to for the test run target
  374. # \arg:TARGET Target to use to retrieve target file to run test on. NAME is adds TARGET as a dependency
  375. # \arg:TEST_REQUIRES(optional) List of system resources that are required to run this test.
  376. # Only available option is "gpu"
  377. # \arg:TEST_COMMAND(optional) - Command which runs the tests
  378. # If not supplied, a default of "AzTestRunner $<TARGET_FILE:${TARGET}> AzRunBenchmarks" will be used
  379. # \arg:COMPONENT (optional) - Scope of the feature area that the test belongs to (eg. physics, graphics, etc.).
  380. # \arg:OUTPUT_FILE_FORMAT(optional) - Format of benchmark output file. Valid options are <console|json|csv>
  381. # If not supplied, json is used as a default and the test run command will output results to
  382. # "${CMAKE_BINARY_DIR}/BenchmarkResults/" directory
  383. # NOTE: Not used if a custom TEST_COMMAND is supplied
  384. # \arg:TIMEOUT (optional) The timeout in seconds for the module. If not set, will have its timeout set by ly_add_test to the default timeout.
  385. function(ly_add_googlebenchmark)
  386. if(NOT PAL_TRAIT_BUILD_TESTS_SUPPORTED)
  387. message(FATAL_ERROR "Platform does not support test targets")
  388. endif()
  389. if(NOT PAL_TRAIT_TEST_GOOGLE_BENCHMARK_SUPPORTED)
  390. return()
  391. endif()
  392. set(one_value_args NAME TARGET OUTPUT_FILE_FORMAT TIMEOUT)
  393. set(multi_value_args TEST_REQUIRES TEST_COMMAND COMPONENT)
  394. cmake_parse_arguments(ly_add_googlebenchmark "${options}" "${one_value_args}" "${multi_value_args}" ${ARGN})
  395. ly_strip_target_namespace(TARGET ${ly_add_googlebenchmark_NAME} OUTPUT_VARIABLE stripped_name)
  396. string(TOLOWER "${ly_add_googlebenchmark_OUTPUT_FILE_FORMAT}" output_file_format_lower)
  397. # Make the BenchmarkResults at configure time so that benchmark results can be stored there
  398. file(MAKE_DIRECTORY "${CMAKE_BINARY_DIR}/BenchmarkResults")
  399. if("${output_file_format_lower}" STREQUAL "console")
  400. set(output_format_args
  401. "--benchmark_out_format=console"
  402. "--benchmark_out=${CMAKE_BINARY_DIR}/BenchmarkResults/${stripped_name}.log"
  403. )
  404. elseif("${output_file_format_lower}" STREQUAL "csv")
  405. set(output_format_args
  406. "--benchmark_out_format=csv"
  407. "--benchmark_out=${CMAKE_BINARY_DIR}/BenchmarkResults/${stripped_name}.csv"
  408. )
  409. else()
  410. set(output_format_args
  411. "--benchmark_out_format=json"
  412. "--benchmark_out=${CMAKE_BINARY_DIR}/BenchmarkResults/${stripped_name}.json"
  413. )
  414. endif()
  415. if(NOT ly_add_googlebenchmark_TEST_COMMAND)
  416. # Use the TARGET parameter as the build target if supplied, otherwise fallback to using the NAME parameter
  417. set(build_target ${ly_add_googlebenchmark_TARGET})
  418. if(NOT build_target)
  419. set(build_target ${ly_add_googlebenchmark_NAME}) # Assume NAME is the TARGET if not specified
  420. endif()
  421. ly_strip_target_namespace(TARGET ${build_target} OUTPUT_VARIABLE build_target)
  422. if(NOT TARGET ${build_target})
  423. message(FATAL_ERROR "A valid build target \"${build_target}\" for test run \"${ly_add_googlebenchmark_NAME}\" has not been found.\
  424. A valid target via the TARGET parameter or a custom TEST_COMMAND must be supplied")
  425. endif()
  426. # If command is not supplied attempts, uses the AzTestRunner to run googlebenchmarks on the supplied TARGET
  427. set(full_test_command $<TARGET_FILE:AZ::AzTestRunner> $<TARGET_FILE:${build_target}> AzRunBenchmarks ${output_format_args})
  428. # Start the test target params and dd the command runner command
  429. # Ideally, we would populate the full command procedurally but the generator expressions won't be expanded by the time we need this data
  430. set(LY_TEST_PARAMS "AzRunUnitTests")
  431. else()
  432. set(full_test_command ${ly_add_googlebenchmark_TEST_COMMAND})
  433. # Remove the generator expressions so we are left with the argument(s) required to run unit tests for executable targets
  434. string(REPLACE ";" "" stripped_test_command ${full_test_command})
  435. string(GENEX_STRIP ${stripped_test_command} stripped_test_command)
  436. # Start the test target params and dd the command runner command
  437. set(LY_TEST_PARAMS "${stripped_test_command}")
  438. endif()
  439. # Set the name of the current test target for storage in the global list
  440. ly_add_test(
  441. NAME ${ly_add_googlebenchmark_NAME}
  442. PARENT_NAME ${ly_add_googlebenchmark_NAME}
  443. TEST_REQUIRES ${ly_add_googlebenchmark_TEST_REQUIRES}
  444. TEST_COMMAND ${full_test_command} ${LY_GOOGLETEST_EXTRA_PARAMS}
  445. TEST_SUITE "benchmark"
  446. LABELS FRAMEWORK_googlebenchmark
  447. TEST_LIBRARY googlebenchmark
  448. TIMEOUT ${ly_add_googlebenchmark_TIMEOUT}
  449. RUNTIME_DEPENDENCIES
  450. ${build_target}
  451. AZ::AzTestRunner
  452. COMPONENT ${ly_add_googlebenchmark_COMPONENT}
  453. )
  454. endfunction()