diff --git a/.github/workflows/ci-archlinux.yml b/.github/workflows/ci-archlinux.yml index 2d3f0c0e6a8..30c51d3725a 100644 --- a/.github/workflows/ci-archlinux.yml +++ b/.github/workflows/ci-archlinux.yml @@ -120,8 +120,6 @@ jobs: tar -czf sunshine.pkg.tar.gz -C pkg . - name: Build PKGBUILD - env: - DISPLAY: :1 id: build shell: bash working-directory: pkg @@ -131,9 +129,6 @@ jobs: source /etc/profile # ensure cuda is in the PATH - # Run Xvfb for headless testing - Xvfb "${DISPLAY}" -screen 0 1024x768x24 & - # Check PKGBUILD sudo -u builder namcap -i PKGBUILD @@ -173,7 +168,7 @@ jobs: name: coverage-Archlinux path: | pkg/src/build/coverage.xml - pkg/src/build/tests/test_results.xml + pkg/src/build/tests/test_results if-no-files-found: error - name: Copy Artifacts diff --git a/.github/workflows/ci-freebsd.yml b/.github/workflows/ci-freebsd.yml index 6b177d513ab..dd4b8c0ead9 100644 --- a/.github/workflows/ci-freebsd.yml +++ b/.github/workflows/ci-freebsd.yml @@ -94,7 +94,7 @@ jobs: x11/libXfixes \ x11/libXrandr \ x11/libXtst \ - x11-servers/xorg-server + x11-servers/xorg-server@xvfb # create symlink for shebang bash compatibility ln -s /usr/local/bin/bash /bin/bash @@ -168,7 +168,7 @@ jobs: run: | set -e cd "${GITHUB_WORKSPACE}" - ninja -C build + cmake --build build - name: Package shell: freebsd {0} @@ -215,13 +215,13 @@ jobs: shell: freebsd {0} run: | set -e - cd "${GITHUB_WORKSPACE}/build/tests" + cd "${GITHUB_WORKSPACE}/build" export DISPLAY=:1 Xvfb ${DISPLAY} -screen 0 1024x768x24 & XVFB_PID=$! - ./test_sunshine --gtest_color=yes --gtest_output=xml:test_results.xml + ctest --output-on-failure kill ${XVFB_PID} @@ -252,7 +252,7 @@ jobs: name: coverage-FreeBSD-${{ matrix.cmake_processor }} path: | build/coverage.xml - build/tests/test_results.xml + build/tests/test_results if-no-files-found: error - name: Upload Artifacts diff --git a/.github/workflows/ci-linux.yml b/.github/workflows/ci-linux.yml index fe9f1866221..ba1d4508dfe 100644 --- a/.github/workflows/ci-linux.yml +++ b/.github/workflows/ci-linux.yml @@ -86,6 +86,9 @@ jobs: sudo make install cd .. && rm -rf libva-* + - name: Setup virtual desktop + uses: LizardByte/actions/actions/virtual_desktop@188c8ccad593e0f68bcf6aacb6bf84f10359d26f # v2026.905.43751 + - name: Build Linux env: BRANCH: ${{ github.head_ref || github.ref_name }} @@ -108,7 +111,7 @@ jobs: working-directory: build run: | # install sunshine to the DESTDIR - DESTDIR=AppDir ninja install + DESTDIR=AppDir cmake --install . test -f AppDir/usr/share/sunshine/udev/rules.d/60-sunshine.rules grep -Fq 'IMPORT{parent}="HID_*"' \ AppDir/usr/share/sunshine/udev/rules.d/60-sunshine.rules @@ -188,9 +191,6 @@ jobs: sudo apt-get clean sudo rm -rf /var/lib/apt/lists/* - - name: Setup virtual desktop - uses: LizardByte/actions/actions/virtual_desktop@188c8ccad593e0f68bcf6aacb6bf84f10359d26f # v2026.905.43751 - - name: Setup uv uses: astral-sh/setup-uv@20cfd1bf945f4377ade1205e4dbc17946fc9a30d # v10.0.1 with: @@ -209,8 +209,8 @@ jobs: - name: Run tests id: test - working-directory: build/tests - run: ./test_sunshine --gtest_color=yes --gtest_output=xml:test_results.xml + working-directory: build + run: ctest --output-on-failure - name: Upload system tray screenshots if: >- @@ -248,7 +248,7 @@ jobs: name: coverage-Linux-${{ matrix.name }} path: | build/coverage.xml - build/tests/test_results.xml + build/tests/test_results if-no-files-found: error - name: Upload Artifacts diff --git a/.github/workflows/ci-macos.yml b/.github/workflows/ci-macos.yml index 85f803e607f..1319b8509af 100644 --- a/.github/workflows/ci-macos.yml +++ b/.github/workflows/ci-macos.yml @@ -87,6 +87,7 @@ jobs: cmake \ doxygen \ graphviz \ + ninja \ node \ pkgconf \ icu4c@78 \ @@ -127,6 +128,7 @@ jobs: mkdir -p build cmake \ -B build \ + -G Ninja \ -S . \ -DBUILD_DOCS="${{ matrix.build_docs }}" \ -DBUILD_WERROR=ON \ @@ -144,7 +146,7 @@ jobs: - name: Build run: | echo "::add-matcher::.github/matchers/gcc.json" - cmake --build build -j "$(sysctl -n hw.ncpu)" + cmake --build build --parallel "$(sysctl -n hw.ncpu)" echo "::remove-matcher owner=gcc::" - name: Package DMG @@ -192,8 +194,8 @@ jobs: - name: Test id: test - working-directory: build/tests - run: ./test_sunshine --gtest_color=yes --gtest_output=xml:test_results.xml + working-directory: build + run: ctest --output-on-failure - name: Upload system tray screenshots if: >- @@ -230,7 +232,7 @@ jobs: name: coverage-${{ matrix.name }} path: | build/coverage.xml - build/tests/test_results.xml + build/tests/test_results if-no-files-found: error - name: Set artifact prefix diff --git a/.github/workflows/ci-windows.yml b/.github/workflows/ci-windows.yml index 417464ded6f..b568fc1161f 100644 --- a/.github/workflows/ci-windows.yml +++ b/.github/workflows/ci-windows.yml @@ -249,7 +249,7 @@ jobs: -DSUNSHINE_PUBLISHER_WEBSITE="https://app.lizardbyte.dev" \ -DSUNSHINE_PUBLISHER_ISSUE_URL="https://app.lizardbyte.dev/support" echo "::add-matcher::.github/matchers/gcc.json" - ninja -C build + cmake --build build echo "::remove-matcher owner=gcc::" - name: Check Windows linkage @@ -351,13 +351,12 @@ jobs: run: cat ./build/cpack_artifacts/_CPack_Packages/win64/WIX/wix.log || true - name: Initialize tray icon - working-directory: build/tests + working-directory: build env: SUNSHINE_CONFIGURE_TRAY_ICONS: '1' run: >- - ./test_sunshine.exe - --gtest_color=yes - --gtest_filter=SystemTrayTest.InitializesTrayForWorkflowConfiguration + ctest --output-on-failure + --tests-regex '^SystemTrayTest\.InitializesTrayForWorkflowConfiguration$' - name: Configure Windows tray screenshots uses: LizardByte/tray/.github/actions/configure-windows-tray-screenshots@master @@ -365,8 +364,8 @@ jobs: - name: Run tests id: test shell: msys2 {0} - working-directory: build/tests - run: ./test_sunshine.exe --gtest_color=yes --gtest_output=xml:test_results.xml + working-directory: build + run: ctest --output-on-failure - name: Upload system tray screenshots if: >- @@ -406,7 +405,7 @@ jobs: name: coverage-${{ matrix.name }} path: | build/coverage.xml - build/tests/test_results.xml + build/tests/test_results if-no-files-found: error - name: Package Windows Debug Info diff --git a/.github/workflows/ci.yml b/.github/workflows/ci.yml index 0c482fbfa44..1e58401c7fd 100644 --- a/.github/workflows/ci.yml +++ b/.github/workflows/ci.yml @@ -252,9 +252,8 @@ jobs: - name: Upload test results uses: codecov/codecov-action@fb8b3582c8e4def4969c97caa2f19720cb33a72f # v7.0.0 with: - disable_search: true + directory: ./_coverage/tests fail_ci_if_error: true - files: ./_coverage/tests/test_results.xml report_type: test_results flags: ${{ matrix.name }} token: ${{ secrets.CODECOV_TOKEN }} diff --git a/cmake/dependencies/libevdev_Sunshine.cmake b/cmake/dependencies/libevdev_Sunshine.cmake index 1358c339e5e..5701889155d 100644 --- a/cmake/dependencies/libevdev_Sunshine.cmake +++ b/cmake/dependencies/libevdev_Sunshine.cmake @@ -20,6 +20,7 @@ else() BUILD_IN_SOURCE 1 CONFIGURE_COMMAND sh /autogen.sh && /configure --prefix= BUILD_COMMAND make + BUILD_BYPRODUCTS /libevdev/.libs/libevdev.a INSTALL_COMMAND "" ) diff --git a/cmake/targets/common.cmake b/cmake/targets/common.cmake index 2aa9f094632..0813ba449eb 100644 --- a/cmake/targets/common.cmake +++ b/cmake/targets/common.cmake @@ -101,6 +101,26 @@ endif() # tests if(BUILD_TESTS) + enable_testing() + + # CMAKE_TEST_LAUNCHER was added in CMake 3.29. Use xvfb-run automatically + # for headless Unix builds while preserving an existing X11 or Wayland + # desktop, such as the one used by the tray screenshot tests. + if(CMAKE_VERSION VERSION_GREATER_EQUAL "3.29" + AND UNIX + AND NOT APPLE + AND NOT DEFINED CMAKE_TEST_LAUNCHER + AND "$ENV{DISPLAY}" STREQUAL "" + AND "$ENV{WAYLAND_DISPLAY}" STREQUAL "") + find_program(SUNSHINE_XVFB_EXECUTABLE NAMES Xvfb NO_CACHE) + find_program(SUNSHINE_XVFB_RUN_EXECUTABLE NAMES xvfb-run NO_CACHE) + + if(SUNSHINE_XVFB_EXECUTABLE AND SUNSHINE_XVFB_RUN_EXECUTABLE) + set(CMAKE_TEST_LAUNCHER "${SUNSHINE_XVFB_RUN_EXECUTABLE}" -a) + message(STATUS "Using xvfb-run for headless tests: ${SUNSHINE_XVFB_RUN_EXECUTABLE}") + endif() + endif() + add_subdirectory(tests) endif() diff --git a/docker/debian.dockerfile b/docker/debian.dockerfile index d34fa56e939..064e50ab073 100644 --- a/docker/debian.dockerfile +++ b/docker/debian.dockerfile @@ -81,13 +81,11 @@ set -e _BUILD # run tests -WORKDIR /build/sunshine/build/tests +WORKDIR /build/sunshine/build RUN <<_TEST #!/bin/bash set -e -export DISPLAY=:1 -Xvfb "${DISPLAY}" -screen 0 1024x768x24 & -./test_sunshine --gtest_color=yes +ctest --output-on-failure _TEST FROM sunshine-base AS sunshine diff --git a/docs/building.md b/docs/building.md index 25e4b270088..478d3429842 100644 --- a/docs/building.md +++ b/docs/building.md @@ -216,7 +216,7 @@ mkdir build ```bash cmake -B build -G Ninja -S . -ninja -C build +cmake --build build ``` > [!TIP] diff --git a/docs/contributing.md b/docs/contributing.md index 113bb173059..7fb74898edf 100644 --- a/docs/contributing.md +++ b/docs/contributing.md @@ -23,8 +23,8 @@ Read our contribution guide in our organization level @tabs{ @tab{CMake | ```bash - cmake -B build -G Ninja -S . --target web-ui - ninja -C build web-ui + cmake -B build -G Ninja -S . + cmake --build build --target web-ui ```} @tab{Manual | ```bash npm run dev @@ -176,9 +176,12 @@ can be disabled by setting the `BUILD_TESTS` CMake option to `OFF`. To run the tests, execute the following command. ```bash -./build/tests/test_sunshine +ctest --test-dir build --output-on-failure ``` +On headless Linux systems using CMake 3.29 or newer, CMake automatically runs the tests through `xvfb-run` when both +`Xvfb` and `xvfb-run` are installed. An existing X11 or Wayland display is used as-is. + To see all available options, run the tests with the `--help` flag. ```bash diff --git a/packaging/linux/Arch/PKGBUILD b/packaging/linux/Arch/PKGBUILD index d28b7430cfd..726e418a23f 100644 --- a/packaging/linux/Arch/PKGBUILD +++ b/packaging/linux/Arch/PKGBUILD @@ -65,7 +65,7 @@ makedepends=( 'desktop-file-utils' "gcc${_gcc_dep_suffix}" 'git' - 'make' + 'ninja' 'nodejs' 'npm' 'python-jinja' # required by the glad OpenGL/EGL loader generator @@ -138,6 +138,7 @@ build() { local _cmake_options=( -S "$pkgname" -B build + -G Ninja -Wno-dev -D BUILD_DOCS=OFF -D BUILD_WERROR=ON @@ -190,16 +191,15 @@ check() { export CC="gcc${_gcc_env_suffix}" export CXX="g++${_gcc_env_suffix}" - cd "${srcdir}/build/tests" + cd "${srcdir}/build" # Do not silently upload misleading coverage if the gcov runtime cannot # write profile data, such as when its version differs from the compiler. - GCOV_EXIT_AT_ERROR=1 ./test_sunshine --gtest_color=yes --gtest_output=xml:test_results.xml + GCOV_EXIT_AT_ERROR=1 \ + ctest --output-on-failure # Generate coverage report # Run gcovr from the build directory (where all .gcda/.gcno files are) # This matches the pattern used in ci-linux.yml - cd "${srcdir}/build" - # Dynamically find the gcov executable from the selected compiler. # This ensures we use the same gcov version that produced the .gcno files. local gcov_path diff --git a/packaging/linux/copr/Sunshine.spec b/packaging/linux/copr/Sunshine.spec index 23203c3e360..0e1084e1e2c 100644 --- a/packaging/linux/copr/Sunshine.spec +++ b/packaging/linux/copr/Sunshine.spec @@ -200,13 +200,9 @@ cuda_supported_architectures=("x86_64" "aarch64") # prepare CMAKE args cmake_args=( - "-B=%{_builddir}/Sunshine/build" - "-G=Unix Makefiles" - "-S=." "-DBUILD_DOCS=OFF" "-DBUILD_WERROR=ON" "-DCMAKE_BUILD_TYPE=Release" - "-DCMAKE_INSTALL_PREFIX=%{_prefix}" "-DSUNSHINE_ASSETS_DIR=%{_datadir}/sunshine" "-DSUNSHINE_EXECUTABLE_PATH=%{_bindir}/sunshine" "-DSUNSHINE_ENABLE_DRM=ON" @@ -391,7 +387,7 @@ NPM_PATH=$(which npm) NODE_PATH=$(which node) cmake_args+=("-DNPM=${NPM_PATH}") -# Add node bin directory to PATH for make +# Add node bin directory to PATH for the build export PATH="$(dirname ${NODE_PATH}):${PATH}" %endif @@ -412,8 +408,8 @@ uv sync \ %endif echo "cmake args:" echo "${cmake_args[@]}" -cmake "${cmake_args[@]}" -make -j$(nproc) -C "%{_builddir}/Sunshine/build" +%cmake ${cmake_args[@]} +%cmake_build %check # validate the metainfo file @@ -422,18 +418,18 @@ appstream-util validate --nonet %{buildroot}%{_metainfodir}/*.metainfo.xml desktop-file-validate %{buildroot}%{_datadir}/applications/*.desktop # run tests -cd %{_builddir}/Sunshine/build -xvfb-run ./tests/test_sunshine +cd %{_builddir}/Sunshine/ +%ctest %install -# Load NVM for Fedora 44+ so npm is available during make install +# Load NVM for Fedora 44+ so npm is available during installation %if 0%{?fedora} > 43 export HOME=${HOME:-/builddir} export NVM_DIR="$HOME/.nvm" [ -s "$NVM_DIR/nvm.sh" ] && \. "$NVM_DIR/nvm.sh" nvm use node -# Add node bin directory to PATH for make install +# Add node bin directory to PATH for installation NODE_PATH=$(which node) export PATH="$(dirname ${NODE_PATH}):${PATH}" @@ -441,8 +437,8 @@ echo "Node.js version: $(node --version)" echo "npm version: $(npm --version)" %endif -cd %{_builddir}/Sunshine/build -%make_install +cd %{_builddir}/Sunshine +%cmake_install %post # Note: this is copied from the postinst script diff --git a/packaging/linux/flatpak/dev.lizardbyte.app.Sunshine.yml b/packaging/linux/flatpak/dev.lizardbyte.app.Sunshine.yml index c6eba43e68e..e64c2d77a13 100644 --- a/packaging/linux/flatpak/dev.lizardbyte.app.Sunshine.yml +++ b/packaging/linux/flatpak/dev.lizardbyte.app.Sunshine.yml @@ -100,7 +100,7 @@ modules: run-tests: true test-rule: "" # empty to disable test-commands: - - npm run serve & xvfb-run tests/test_sunshine --gtest_color=yes + - npm run serve & ctest --output-on-failure sources: - generated-sources.json - type: git diff --git a/packaging/sunshine.rb b/packaging/sunshine.rb index 29add83b27e..2adf3b71089 100644 --- a/packaging/sunshine.rb +++ b/packaging/sunshine.rb @@ -50,6 +50,7 @@ class Sunshine < Formula depends_on "cmake" => :build depends_on "doxygen" => :build if build.with? "docs" depends_on "graphviz" => :build if build.with? "docs" + depends_on "ninja" => :build depends_on "node" => :build depends_on "pkgconf" => :build depends_on "boost" @@ -369,9 +370,11 @@ def relative_lcov_record(record, source_prefixes) source_path = Pathname.new(lines[source_index].delete_prefix("SF:").strip).cleanpath.to_s # Homebrew remaps the formula build path to ".". LLVM may then resolve that - # relative path from CMake's compilation directory at "build/tests". + # relative path from the generator's compilation directory under "build". relative_source_path = if source_path.start_with?("build/tests/src/") source_path.delete_prefix("build/tests/") + elsif source_path.start_with?("build/src/") + source_path.delete_prefix("build/") elsif source_path.start_with?("src/") source_path else @@ -419,12 +422,12 @@ def build_cmake_args end def build_and_install_project - system "cmake", "-S", ".", "-B", "build", "-G", "Unix Makefiles", + system "cmake", "-S", ".", "-B", "build", "-G", "Ninja", *std_cmake_args, *build_cmake_args - system "make", "-C", "build" - system "make", "-C", "build", "install" + system "cmake", "--build", "build" + system "cmake", "--install", "build" end def install_platform_specific_files @@ -498,6 +501,9 @@ def caveats SF:build/tests/src/remapped_from_compile_dir.cpp DA:1,1 end_of_record + SF:build/src/remapped_from_ninja_compile_dir.cpp + DA:1,1 + end_of_record SF:src/relative.cpp DA:1,1 end_of_record @@ -518,6 +524,9 @@ def caveats SF:src/remapped_from_compile_dir.cpp DA:1,1 end_of_record + SF:src/remapped_from_ninja_compile_dir.cpp + DA:1,1 + end_of_record SF:src/relative.cpp DA:1,1 end_of_record diff --git a/scripts/linux_build.sh b/scripts/linux_build.sh index 5254a97c031..89c2451c94f 100755 --- a/scripts/linux_build.sh +++ b/scripts/linux_build.sh @@ -539,7 +539,12 @@ function install_cuda() { echo "cuda url: ${url}" wget "$url" --max-redirect=0 --progress=bar:force:noscroll -q --show-progress -O "${build_dir}/cuda.run" chmod a+x "${build_dir}/cuda.run" - "${build_dir}/cuda.run" --silent --toolkit --toolkitpath="${build_dir}/cuda" --no-opengl-libs --no-man-page --no-drm "$cuda_override_arg" + # The NVIDIA runfile tries to open a graphical installer whenever DISPLAY is + # set, even in silent mode. Hide the virtual desktop from this command only. + ( + unset DISPLAY WAYLAND_DISPLAY + "${build_dir}/cuda.run" --silent --toolkit --toolkitpath="${build_dir}/cuda" --no-opengl-libs --no-man-page --no-drm "$cuda_override_arg" + ) rm "${build_dir}/cuda.run" apply_cuda_patches "${build_dir}/cuda" @@ -644,8 +649,8 @@ function run_step_deps() { tar -xzf "${DOXYGEN}.tar.gz" cd "${DOXYGEN}-${doxygen_min}" cmake -DCMAKE_BUILD_TYPE=Release -G="Ninja" -B="build" -S="." - ninja -C "build" -j"${num_processors}" - ${sudo_cmd} ninja -C "build" install + cmake --build "build" --parallel "${num_processors}" + ${sudo_cmd} cmake --install "build" popd else echo "${DOXYGEN} version not in range, skipping docs" @@ -772,7 +777,7 @@ function run_step_build() { setup_nvm_environment # Build the project - ninja -C "build" + cmake --build "build" return 0 } diff --git a/scripts/macos_build.sh b/scripts/macos_build.sh index 70a276480b9..f515d61d386 100755 --- a/scripts/macos_build.sh +++ b/scripts/macos_build.sh @@ -30,6 +30,7 @@ required_formulas=( "cmake" "doxygen" "graphviz" + "ninja" "node" "pkgconf" "icu4c@78" @@ -95,6 +96,7 @@ function run_step_cmake() { # prepare CMAKE args cmake_args=( "-B=build" + "-G=Ninja" "-S=." "-DBUILD_DOCS=${build_docs}" "-DBUILD_TESTS=${build_tests}" @@ -138,7 +140,7 @@ function run_step_cmake() { function run_step_build() { echo "Running step: Build" - cmake --build "${build_dir}" -j "${num_processors}" + cmake --build "${build_dir}" --parallel "${num_processors}" return 0 } diff --git a/tests/CMakeLists.txt b/tests/CMakeLists.txt index 360ae84d022..68b962ad950 100644 --- a/tests/CMakeLists.txt +++ b/tests/CMakeLists.txt @@ -170,6 +170,15 @@ add_executable(${PROJECT_NAME} ${TEST_SOURCES} ${SUNSHINE_SOURCES}) +include(GoogleTest) +gtest_discover_tests(${PROJECT_NAME} + DISCOVERY_MODE PRE_TEST + EXTRA_ARGS --gtest_color=yes + NO_PRETTY_TYPES + NO_PRETTY_VALUES + PROPERTIES RUN_SERIAL TRUE + XML_OUTPUT_DIR "${CMAKE_CURRENT_BINARY_DIR}/test_results") + # Copy files needed for config consistency tests to build directory # This ensures both CLI and CLion can access the same files relative to the test executable # Using configure_file ensures files are copied when they change between builds