Compare commits

...
Author SHA1 Message Date
SoftFever 6a7e8e784c Require numpy for the plugin tests in CI 2026-09-28 14:48:30 +08:00
SoftFever c09902aa44 Merge branch 'main' into feature/enable-unit-tests-for-plugins 2026-09-28 12:40:41 +08:00
SoftFever bd3140d202 fix Windows 2026-09-28 11:40:52 +08:00
SoftFever 88586eea44 enable python unit test 2026-09-09 00:10:02 +08:00
5 changed files with 92 additions and 11 deletions
+8
View File
@@ -44,6 +44,14 @@ jobs:
uses: actions/download-artifact@v8 uses: actions/download-artifact@v8
with: with:
name: ${{ inputs.artifact }} name: ${{ inputs.artifact }}
# run_unit_tests.sh installs the plugin tests' numpy with the uv the build stages
# beside them; the Windows arm64 build bundles none, so put one on PATH there.
- name: Install uv
if: runner.os == 'Windows' && runner.arch == 'ARM64'
uses: astral-sh/setup-uv@v10.2.0
with:
version: "0.11.21" # ORCA_UV_VERSION in CMakeLists.txt
enable-cache: false
- uses: lukka/get-cmake@latest - uses: lukka/get-cmake@latest
with: with:
cmakeVersion: "~4.3.0" # use most recent 4.3.x version cmakeVersion: "~4.3.0" # use most recent 4.3.x version
+3 -1
View File
@@ -52,4 +52,6 @@ internal_docs/
__pycache__/ __pycache__/
*.pyc *.pyc
*.opc *.opc
docs/superpowers/ /.test/
docs/superpowers/
ctest_results.xml
+48 -1
View File
@@ -2,7 +2,8 @@
# This file is made to support the unit tests workflow. # This file is made to support the unit tests workflow.
# It should only require the directories build/tests, scripts/, and tests/ to function, # It should only require the directories build/tests, scripts/, and tests/ to function,
# and cmake (with ctest) installed. # and cmake (with ctest) installed -- plus network access to PyPI whenever numpy has to
# be installed into a freshly built test tree (see below).
# (otherwise, update the workflow too, but try to avoid to keep things self-contained) # (otherwise, update the workflow too, but try to avoid to keep things self-contained)
# #
# Usage: run_unit_tests.sh [TEST_DIR] [BUILD_CONFIG] # Usage: run_unit_tests.sh [TEST_DIR] [BUILD_CONFIG]
@@ -18,6 +19,52 @@ cd "${ROOT_DIR}" || exit 1
TEST_DIR="${1:-build/tests}" TEST_DIR="${1:-build/tests}"
BUILD_CONFIG="${2:-}" BUILD_CONFIG="${2:-}"
# The slic3rutils plugin-host tests build numpy arrays through the CPython copied next
# to the test binary (see tests/slic3rutils/CMakeLists.txt), which ships no numpy.
# Install it with the uv staged beside that runtime -- the tool the app installs plugin
# dependencies with -- straight into the interpreter's own site-packages: no pip needed
# in the runtime, no PYTHONPATH. Re-checked every run because a rebuild of the test
# target re-copies the runtime; needs network whenever it installs. Pinned so a numpy
# release cannot change results on its own.
NUMPY_VERSION="2.5.3"
# Without numpy those tests assert the numpy-absent error path instead, so a local run
# only warns. Under CI it fails the run, which would otherwise stay green while silently
# dropping the array coverage. (The Flatpak leg runs this inside `flatpak build`, whose
# minimal environment has no CI, and its offline build stages no uv, so numpy stays
# best-effort there.)
numpy_unavailable() {
if [ -n "${CI:-}" ]; then
echo "error: $1" >&2
exit 1
fi
echo "warning: $1; the numpy-backed binding tests will cover only the numpy-absent path."
}
has_pinned_numpy() {
"${python_exe}" -c "import sys, numpy; sys.exit(numpy.__version__ != '${NUMPY_VERSION}')" >/dev/null 2>&1
}
find_args=("${TEST_DIR}" \( -path '*/python/bin/python3' -o -path '*/python/python.exe' \))
# Multi-config trees hold one copy per configuration; only bootstrap the one being run.
[ -n "${BUILD_CONFIG}" ] && find_args+=(-path "*/${BUILD_CONFIG}/*")
python_exe="$(find "${find_args[@]}" -print -quit 2>/dev/null)"
if [ -z "${python_exe}" ]; then
numpy_unavailable "no bundled Python under ${TEST_DIR}"
elif ! has_pinned_numpy; then
uv_exe="${python_exe%/python/*}/tools/uv/uv"
# Builds that bundle no uv (Windows arm64) fall back to one on PATH.
[ -x "${uv_exe}" ] || uv_exe="$(command -v uv)"
echo "Installing numpy ${NUMPY_VERSION} into the embedded test interpreter (${python_exe})..."
if [ -z "${uv_exe}" ]; then
numpy_unavailable "no uv staged beside the tests or on PATH"
elif ! "${uv_exe}" pip install --python "${python_exe}" --only-binary :all: "numpy==${NUMPY_VERSION}" \
|| ! has_pinned_numpy; then
numpy_unavailable "could not install numpy ${NUMPY_VERSION} into ${python_exe}"
fi
fi
# Run the whole suite, excluding tests tagged [NotWorking] and tests labelled RequiresApp, # Run the whole suite, excluding tests tagged [NotWorking] and tests labelled RequiresApp,
# which run the built orca-slicer binary that this directory does not contain. # which run the built orca-slicer binary that this directory does not contain.
# --no-tests=error fails the job if the filter matches nothing (instead of passing green). # --no-tests=error fails the job if the filter matches nothing (instead of passing green).
+10 -5
View File
@@ -345,16 +345,21 @@ boost::filesystem::path find_bundled_python_home()
fs::path bundle_python = fs::path(resources_dir()).parent_path() / "MacOS" / "python"; fs::path bundle_python = fs::path(resources_dir()).parent_path() / "MacOS" / "python";
if (valid_python_home(bundle_python)) if (valid_python_home(bundle_python))
return bundle_python; return bundle_python;
#elif defined(_WIN32) #elif !defined(_WIN32)
fs::path exe_python = boost::dll::program_location().parent_path() / "python";
if (valid_python_home(exe_python))
return exe_python;
#else
fs::path linux_python = fs::path(resources_dir()).parent_path() / "lib" / "python"; fs::path linux_python = fs::path(resources_dir()).parent_path() / "lib" / "python";
if (valid_python_home(linux_python)) if (valid_python_home(linux_python))
return linux_python; return linux_python;
#endif #endif
// Next to the executable: the Windows install layout, and the runtime copied
// beside every platform's unit-test binary (tests/slic3rutils/CMakeLists.txt).
// The CI test runner only receives the build/tests tree, so the candidates
// below -- all of which point into the deps or install trees -- never resolve
// there.
fs::path exe_python = boost::dll::program_location().parent_path() / "python";
if (valid_python_home(exe_python))
return exe_python;
fs::path configured_python = ORCA_BUNDLED_PYTHON_ROOT; fs::path configured_python = ORCA_BUNDLED_PYTHON_ROOT;
if (!configured_python.empty() && valid_python_home(configured_python)) if (!configured_python.empty() && valid_python_home(configured_python))
return configured_python; return configured_python;
+23 -4
View File
@@ -49,9 +49,16 @@ if (WIN32)
COMMENT "Copying Python runtime for slic3rutils plugin host API tests" COMMENT "Copying Python runtime for slic3rutils plugin host API tests"
VERBATIM VERBATIM
) )
elseif (APPLE) elseif (NOT FLATPAK)
target_link_options(${_TEST_NAME}_tests PRIVATE # The CI unit-test runner only receives the build/tests tree, so both the
"LINKER:-rpath,@executable_path/python/lib") # interpreter and the libpython the test binary links have to travel next to
# the executable; find_bundled_python_home() picks the copy up from there.
if (APPLE)
target_link_options(${_TEST_NAME}_tests PRIVATE
"LINKER:-rpath,@executable_path/python/lib")
else ()
set_property(TARGET ${_TEST_NAME}_tests APPEND PROPERTY BUILD_RPATH "$ORIGIN/python/lib")
endif ()
add_custom_command(TARGET ${_TEST_NAME}_tests POST_BUILD add_custom_command(TARGET ${_TEST_NAME}_tests POST_BUILD
COMMAND ${CMAKE_COMMAND} -E rm -rf COMMAND ${CMAKE_COMMAND} -E rm -rf
@@ -59,7 +66,7 @@ elseif (APPLE)
COMMAND ${CMAKE_COMMAND} -E copy_directory COMMAND ${CMAKE_COMMAND} -E copy_directory
"${CMAKE_PREFIX_PATH}/libpython" "${CMAKE_PREFIX_PATH}/libpython"
"$<TARGET_FILE_DIR:${_TEST_NAME}_tests>/python" "$<TARGET_FILE_DIR:${_TEST_NAME}_tests>/python"
COMMENT "Copying Python runtime for macOS plugin host API tests" COMMENT "Copying Python runtime for the plugin host API tests"
VERBATIM VERBATIM
) )
elseif (FLATPAK) elseif (FLATPAK)
@@ -76,4 +83,16 @@ elseif (FLATPAK)
) )
endif() endif()
# scripts/run_unit_tests.sh installs the tests' numpy into that runtime with this uv,
# staged where the app build tree keeps it (<exe dir>/tools/uv, see src/CMakeLists.txt).
if (ORCA_BUNDLED_UV_EXECUTABLE)
add_custom_command(TARGET ${_TEST_NAME}_tests POST_BUILD
COMMAND ${CMAKE_COMMAND} -E make_directory "$<TARGET_FILE_DIR:${_TEST_NAME}_tests>/tools/uv"
COMMAND ${CMAKE_COMMAND} -E copy_if_different "${ORCA_BUNDLED_UV_EXECUTABLE}"
"$<TARGET_FILE_DIR:${_TEST_NAME}_tests>/tools/uv/${ORCA_BUNDLED_UV_FILENAME}"
COMMENT "Copying uv for the plugin host API tests"
VERBATIM
)
endif()
orcaslicer_discover_tests(${_TEST_NAME}_tests) orcaslicer_discover_tests(${_TEST_NAME}_tests)