From 126f3bcfc15d0ef3d4cffdb418e22d6921435d55 Mon Sep 17 00:00:00 2001 From: Campbell Barton Date: Thu, 26 Oct 2023 15:19:33 +1100 Subject: [PATCH] Tests: support running graphical tests as part of CTests User a Blender wrapper `tests/utils/blender_headless.py` to runs a graphical instance of Blender within a headless weston compositor. Currently only WAYLAND is supported as a back-end, support for other platforms is possible. The tests can run from X11 since the tests don't depend on existing instances of X11 or WAYLAND. - Each test runs a separate headless instance of WESTON since the overhead is minimal, this allows tests to run in parallel without interfering with each other. - There is a CMake option WESTON_BIN, when left empty the weston from LIBDIR is used. Otherwise this can point to the weston binary installed on the users system. - In most cases simulated events are needed to implement these tests (running blender with `--enable-event-simulate`). - This commit adds 14 undo tests - simulating user interaction as well as undo/redo actions, ensuring the desired result is reached. Other kinds of UI tests could be added in the future. Ref !114164 --- CMakeLists.txt | 16 ++++++ tests/python/CMakeLists.txt | 102 +++++++++++++++++++++++++++++++++++- 2 files changed, 116 insertions(+), 2 deletions(-) diff --git a/CMakeLists.txt b/CMakeLists.txt index 84d4424ec42..a35d267513e 100644 --- a/CMakeLists.txt +++ b/CMakeLists.txt @@ -761,6 +761,18 @@ option(WITH_GTESTS "Enable GTest unit testing" OFF) option(WITH_OPENGL_RENDER_TESTS "Enable OpenGL render related unit testing (Experimental)" OFF) option(WITH_OPENGL_DRAW_TESTS "Enable OpenGL UI drawing related unit testing (Experimental)" OFF) option(WITH_COMPOSITOR_REALTIME_TESTS "Enable regression testing for realtime compositor" OFF) +if(UNIX AND NOT (APPLE OR HAIKU)) + option(WITH_UI_TESTS "\ +Enable user-interface tests using a headless display server. \ +Currently this depends on WITH_GHOST_WAYLAND and the weston compositor \ +(Experimental)" + OFF + ) +else() + # TODO: support running GUI tests on other platforms. + set(WITH_UI_TESTS OFF) +endif() + # NOTE: All callers of this must add `TEST_PYTHON_EXE_EXTRA_ARGS` before any other arguments. set(TEST_PYTHON_EXE "" CACHE PATH "Python executable to run unit tests") mark_as_advanced(TEST_PYTHON_EXE) @@ -1156,6 +1168,10 @@ endif() set_and_warn_incompatible(WITH_HEADLESS WITH_XR_OPENXR OFF) set_and_warn_incompatible(WITH_GHOST_SDL WITH_XR_OPENXR OFF) +if(WITH_UI_TESTS) + set_and_warn_dependency(WITH_GHOST_WAYLAND WITH_UI_TESTS OFF) +endif() + if(WITH_BUILDINFO) find_package(Git) set_and_warn_library_found("Git" GIT_FOUND WITH_BUILDINFO) diff --git a/tests/python/CMakeLists.txt b/tests/python/CMakeLists.txt index c0aaf587396..94030d144bf 100644 --- a/tests/python/CMakeLists.txt +++ b/tests/python/CMakeLists.txt @@ -22,10 +22,10 @@ file(MAKE_DIRECTORY ${TEST_OUT_DIR}/blendfile_io) # endif() # Run Blender command with parameters. -function(add_blender_test testname) +function(add_blender_test_impl testname exe) add_test( NAME ${testname} - COMMAND "${TEST_BLENDER_EXE}" ${TEST_BLENDER_EXE_PARAMS} ${ARGN} + COMMAND ${exe} ${ARGN} ) # Don't fail tests on leaks since these often happen in external libraries that we can't fix. @@ -41,6 +41,68 @@ function(add_blender_test testname) endif() endfunction() +function(add_blender_test testname) + add_blender_test_impl( + "${testname}" + "${TEST_BLENDER_EXE}" + ${TEST_BLENDER_EXE_PARAMS} + ${ARGN} + ) +endfunction() + +if(WITH_UI_TESTS) + set(_blender_headless_env_vars "BLENDER_BIN=${TEST_BLENDER_EXE}") + + # Currently only WAYLAND is supported, support for others may be added later. + # In this case none of the WESTON environment variables will be used. + if(WITH_GHOST_WAYLAND) + set(_weston_bin_in_libdir OFF) + if(DEFINED LIBDIR) + set(_weston_bin_default "${LIBDIR}/wayland_weston/bin/weston") + else() + set(_weston_bin_default "weston") + endif() + set(WESTON_BIN "${_weston_bin_default}" CACHE STRING "\ +The location of weston, leave blank for the default location." + ) + mark_as_advanced(WESTON_BIN) + if((DEFINED LIBDIR) AND ("${WESTON_BIN}" STREQUAL "${_weston_bin_default}")) + set(_weston_bin_in_libdir ON) + endif() + + list(APPEND _blender_headless_env_vars + "WESTON_BIN=${WESTON_BIN}" + ) + + if(_weston_bin_in_libdir) + list(APPEND _blender_headless_env_vars + "WAYLAND_ROOT_DIR=${LIBDIR}/wayland" + "WESTON_ROOT_DIR=${LIBDIR}/wayland_weston" + ) + endif() + endif() + + function(add_blender_test_headless testname) + # Remove `--background` so headless execution uses a GUI + # (within a headless graphical environment). + set(EXE_PARAMS ${TEST_BLENDER_EXE_PARAMS}) + list(REMOVE_ITEM EXE_PARAMS --background) + add_blender_test_impl( + "${testname}" + "${TEST_PYTHON_EXE}" + "${CMAKE_SOURCE_DIR}/tests/utils/blender_headless.py" + # NOTE: attempting to maximize the window causes problems with a headless `weston`, + # while this could be investigated, use windowed mode instead. + # Use a window size that balances software GPU rendering with enough room to use the UI. + --factory-startup + -p 0 0 800 600 + "${EXE_PARAMS}" + "${ARGN}" + ) + set_tests_properties(${testname} PROPERTIES ENVIRONMENT "${_blender_headless_env_vars}") + endfunction() +endif() + # Run Python script outside Blender. function(add_python_test testname testscript) if(NOT TEST_PYTHON_EXE) @@ -1000,6 +1062,42 @@ else() endif() +# ------------------------------------------------------------------------------ +# Headless GUI Tests + +if(WITH_UI_TESTS) + # This could be generated with: + # `"${TEST_PYTHON_EXE}" "${TEST_SRC_DIR}/ui_simulate/run.py" --list-tests` + # list explicitly so changes bisecting/updated are sure to re-run CMake. + set(_undo_tests + test_undo.text_editor_edit_mode_mix + test_undo.text_editor_simple + test_undo.view3d_edit_mode_multi_window + test_undo.view3d_font_edit_mode_simple + test_undo.view3d_mesh_edit_separate + test_undo.view3d_mesh_particle_edit_mode_simple + test_undo.view3d_multi_mode_multi_window + test_undo.view3d_multi_mode_select + test_undo.view3d_sculpt_dyntopo_and_edit + test_undo.view3d_sculpt_dyntopo_simple + test_undo.view3d_sculpt_with_memfile_step + test_undo.view3d_simple + test_undo.view3d_texture_paint_complex + test_undo.view3d_texture_paint_simple + ) + foreach(ui_test ${_undo_tests}) + add_blender_test_headless( + "bf_ui_${ui_test}" + --enable-event-simulate + --python "${TEST_SRC_DIR}/ui_simulate/run_blender_setup.py" + -- + --tests "${ui_test}" + ) + endforeach() + unset(_undo_tests) +endif() + + add_subdirectory(collada) # TODO: disabled for now after collection unification