[PR #399] [CLOSED] ci: add image smoke-test harness + Wayland resolution integration tests #443

Closed
opened 2026-10-15 13:00:37 +00:00 by bsakaguchi · 0 comments
Owner

📋 Pull Request Information

Original PR: https://github.com/games-on-whales/wolf/pull/399
Author: @JBailes
Created: 4/24/2026
Status: ❌ Closed

Base: stable ← Head: ci/image-smoke-harness


📝 Commits (8)

  • 51edca5 ci: add wolf image smoke-test harness
  • e42d59c tests: wayland resolution-change integration tests
  • 36687d2 ci: fix workflows for fork-based pull requests
  • 011ea85 tests: additional Wayland resolution integration cases
  • cc346de tests: revive [WAYLAND] Catch2 suite under LINK_RUST_WAYLAND=ON
  • 09e74e8 Merge remote-tracking branch 'origin/stable' into ci/image-smoke-harness
  • d52547a ci: fix smoke-test gst plugin assertions
  • ad2d802 ci: drop dead liblibgstwaylanddisplay COPY from runtime stage

📊 Changes

8 files changed (+1086 additions, -10 deletions)

View changed files

📝 .github/workflows/docker-build.yml (+23 -0)
➕ bin/test-image.sh (+178 -0)
➕ bin/tests/lib.sh (+118 -0)
➕ docker/tests/smoke.sh (+80 -0)
📝 docker/wolf.Dockerfile (+3 -2)
📝 src/core/src/platforms/linux/virtual-display/wayland-display.cpp (+29 -0)
📝 tests/platforms/linux/wayland-client.hpp (+232 -3)
📝 tests/platforms/linux/wayland-display.cpp (+423 -5)

📄 Description

Summary

Layered testing for wolf, mirroring games-on-whales/gow#321:

  1. Image-smoke harness — bin/test-image.sh + docker/tests/smoke.sh wired into docker-build.yml. Catches "builds clean but crashes on startup" regressions in every PR.
  2. Catch2 Wayland resolution integration tests — ten new [WAYLAND][resolution] TEST_CASEs in tests/platforms/linux/wayland-display.cpp that drive a real Wayland client against the virtual display and assert what the client actually observes when Wolf changes the streamed resolution at runtime.
  3. Revives the [WAYLAND] Catch2 suite under LINK_RUST_WAYLAND=ON. The tag had been dark since the gstreamer-plugin refactor removed the legacy free-function declarations from core/virtual-display.hpp and grew NEW-signature entry points that the LINK_RUST_WAYLAND=ON impl hadn't caught up to. This PR forward-declares the legacy API test-locally, adds the missing NEW-signature linker stubs + input-class destructors in the RUST-wayland impl, and relaxes a handful of assertions that assumed hardware DRM / a client-set max_size. Net result: all 12 [WAYLAND] tests compile and pass.

Image-smoke layer (bin/test-image.sh)

Three sub-layers, all run against the just-built image:

  1. Structural — docker inspect: image present, /entrypoint.sh is the entrypoint, org.opencontainers.image.source label set, all six Moonlight ports declared EXPOSE.
  2. Init smoke — sentinel CMD runs every /etc/cont-init.d/*.sh script inherited from the GOW base image as root, then exits. Catches regressions in user/device/nvidia setup.
  3. Image smoke (docker/tests/smoke.sh) — /wolf/wolf and /wolf/fake-udev present and ldd-clean; fake-udev --help runs; the custom gst-plugin-waylanddisplay is present in GST_PLUGIN_PATH and loads via gst-inspect-1.0 waylanddisplay; Xwayland on PATH, /opt/gow/startup-app.sh staged, key Dockerfile-ENV vars survive cont-init.

Shared helpers in bin/tests/lib.sh bind-mount at /smoke-common, mirroring the gow convention. CI wiring: docker-build.yml's Build step gains load: ${{ steps.prep.outputs.push != 'true' }} so fork PRs still end up with a locally-tagged image for the harness. A new Smoke-test step runs after build.

Catch2 [WAYLAND][resolution] tests

Extends the existing tests/platforms/linux/wayland-client.hpp scaffolding and appends ten new TEST_CASEs tagged [WAYLAND][resolution].

Client-side plumbing added to wayland-client.hpp:

  • OutputEvent + ToplevelConfigureEvent types with TSQueues on WClientState
  • wl_output listener bound in the registry callback (geometry / mode / done / scale / name / description)
  • xdg_toplevel listener bound in w_display_create_window
  • Helpers: drain_output_events, drain_toplevel_configure_events, latest_mode, latest_geometry, w_roundtrip_n
  • Forward-declarations for the legacy free-function API (test-local, keeps production header clean). Default render_node = "software" for CI portability.

New TEST_CASEs (via make_resolution_harness()):

  1. Output advertises configured mode to client on bind
  2. Toplevel receives initial configure with window size
  3. Resolution change propagates to connected client
  4. Multiple resolution toggles each propagate
  5. Framerate change updates wl_output.mode.refresh
  6. Client never sees resolution larger than current output
  7. Toplevel max_size clamps configure after resolution change
  8. Rapid back-to-back resolution changes converge on the final mode
  9. Idempotent same-resolution VideoInfo does not break the client
  10. Keyboard input still delivers after a mid-session resize

These tests exercise the same regression path as games-on-whales/gst-wayland-display#27 — covering gstreamer → Rust → Wayland → client in both repos so either side can localise a regression.

Three surgical changes to make the entire [WAYLAND] tag compile + pass:

  • Test-local forward-declarations in wayland-client.hpp for the legacy free-function API (which lives in src/core/.../wayland-display.cpp but isn't declared in the production header). Default render_node = "software" for sandbox portability.
  • Linker stubs in src/core/src/platforms/linux/virtual-display/wayland-display.cpp for the NEW-signature create_wayland_display(gst_element_ptr, string) and get_wayland_socket_name that libwolf_runner.so now references, plus = default destructors for WaylandMouse / WaylandKeyboard / WaylandTouchScreen (declared in the header but previously only implemented in the LINK_RUST_WAYLAND=OFF impl). The stubs log a warning and return empty; the LINK_RUST_WAYLAND=ON path is test-only.
  • Test assertion fixes: (a) wrap Wayland{Mouse,Keyboard} explicitly through the underlying variant type before storing into std::optional<std::variant<...>> — libstdc++ 14+ no longer chains that conversion implicitly. (b) Relax the [WAYLAND][resolution] cases' configure-size assertions: when the client has not set xdg_toplevel.max_size, the compositor emits configure(0, 0) (xdg-shell's "client picks"), so assertions are on wl_output.mode dimensions + configure-arrived rather than configure width/height. The max_size clamps case sets max_size explicitly and continues to assert bounds directly. (c) graphic_devices SizeIs(2) relaxed to accept the software path (empty device list).

Verification

Built libgstwaylanddisplay from games-on-whales/gst-wayland-display#27 (the companion fix + Rust-level integration tests) and linked wolftests against it:

PKG_CONFIG_PATH=… cmake -DLINK_RUST_WAYLAND=ON -DBUILD_TESTING=ON …
cmake --build . --target wolftests
./tests/wolftests '[WAYLAND]' --reporter junit
# → <testsuite name="wolftests" errors="0" failures="0" tests="182" …>

All 12 [WAYLAND] cases pass. Red-green verified by temporarily re-introducing the early return in wayland-display-core/src/comp/mod.rs apply_video_info — 6 of 10 [WAYLAND][resolution] cases go red, confirming the suite catches the regression the companion PR protects against.

Deliberate omissions

  • No variant flag. gow#321 needed --variant fedora for Fedora images; wolf ships only the Ubuntu 25.04 runtime stage.
  • No "launch wolf for N seconds and grep logs" check. Wolf has no --version / --help, so a launch-smoke would need a tmpfs cfg dir and a kill-timer — fragile as a layer-3 static assertion.

Test plan

  • This PR's CI run — the image-smoke harness is wired into docker-build.yml, so the build-and-push is itself the first harness run.
  • Run image-smoke locally once available: docker pull ghcr.io/games-on-whales/wolf:edge && ./bin/test-image.sh ghcr.io/games-on-whales/wolf:edge → expect == PASS ==.
  • Run Catch2 [WAYLAND] locally: build wolftests with -DLINK_RUST_WAYLAND=ON, ./tests/wolftests '[WAYLAND]' → expect 12 passing cases.

🔄 This issue represents a GitHub Pull Request. It cannot be merged through Gitea due to API limitations.

## 📋 Pull Request Information **Original PR:** https://github.com/games-on-whales/wolf/pull/399 **Author:** [@JBailes](https://github.com/JBailes) **Created:** 4/24/2026 **Status:** ❌ Closed **Base:** `stable` ← **Head:** `ci/image-smoke-harness` --- ### 📝 Commits (8) - [`51edca5`](https://github.com/games-on-whales/wolf/commit/51edca5fb58c4ce0f04f79e81aa68027cf081e21) ci: add wolf image smoke-test harness - [`e42d59c`](https://github.com/games-on-whales/wolf/commit/e42d59ccd8d19193dd5cbe4a154df861c618330b) tests: wayland resolution-change integration tests - [`36687d2`](https://github.com/games-on-whales/wolf/commit/36687d2e0f9aa08fb6a3ace38c1f2ab6f0ed49d8) ci: fix workflows for fork-based pull requests - [`011ea85`](https://github.com/games-on-whales/wolf/commit/011ea858b548b9890768801ec291b305fcdaf37e) tests: additional Wayland resolution integration cases - [`cc346de`](https://github.com/games-on-whales/wolf/commit/cc346de44b643a56d3fc3d8de42d7739403564f4) tests: revive [WAYLAND] Catch2 suite under LINK_RUST_WAYLAND=ON - [`09e74e8`](https://github.com/games-on-whales/wolf/commit/09e74e876579791a06e07724163a1c9d0ef419c2) Merge remote-tracking branch 'origin/stable' into ci/image-smoke-harness - [`d52547a`](https://github.com/games-on-whales/wolf/commit/d52547a53c97ab99b454734dcef66d7bb746b4f7) ci: fix smoke-test gst plugin assertions - [`ad2d802`](https://github.com/games-on-whales/wolf/commit/ad2d802c61481e6f5ad7f8c17bafb9884041ba5c) ci: drop dead liblibgstwaylanddisplay COPY from runtime stage ### 📊 Changes **8 files changed** (+1086 additions, -10 deletions) <details> <summary>View changed files</summary> 📝 `.github/workflows/docker-build.yml` (+23 -0) ➕ `bin/test-image.sh` (+178 -0) ➕ `bin/tests/lib.sh` (+118 -0) ➕ `docker/tests/smoke.sh` (+80 -0) 📝 `docker/wolf.Dockerfile` (+3 -2) 📝 `src/core/src/platforms/linux/virtual-display/wayland-display.cpp` (+29 -0) 📝 `tests/platforms/linux/wayland-client.hpp` (+232 -3) 📝 `tests/platforms/linux/wayland-display.cpp` (+423 -5) </details> ### 📄 Description ## Summary Layered testing for wolf, mirroring games-on-whales/gow#321: 1. **Image-smoke harness** — `bin/test-image.sh` + `docker/tests/smoke.sh` wired into `docker-build.yml`. Catches "builds clean but crashes on startup" regressions in every PR. 2. **Catch2 Wayland resolution integration tests** — ten new `[WAYLAND][resolution]` TEST_CASEs in `tests/platforms/linux/wayland-display.cpp` that drive a real Wayland client against the virtual display and assert what the client actually observes when Wolf changes the streamed resolution at runtime. 3. **Revives the `[WAYLAND]` Catch2 suite under `LINK_RUST_WAYLAND=ON`.** The tag had been dark since the gstreamer-plugin refactor removed the legacy free-function declarations from `core/virtual-display.hpp` and grew NEW-signature entry points that the `LINK_RUST_WAYLAND=ON` impl hadn't caught up to. This PR forward-declares the legacy API test-locally, adds the missing NEW-signature linker stubs + input-class destructors in the RUST-wayland impl, and relaxes a handful of assertions that assumed hardware DRM / a client-set `max_size`. **Net result: all 12 `[WAYLAND]` tests compile and pass.** ### Image-smoke layer (`bin/test-image.sh`) Three sub-layers, all run against the just-built image: 1. **Structural** — `docker inspect`: image present, `/entrypoint.sh` is the entrypoint, `org.opencontainers.image.source` label set, all six Moonlight ports declared `EXPOSE`. 2. **Init smoke** — sentinel CMD runs every `/etc/cont-init.d/*.sh` script inherited from the GOW base image as root, then exits. Catches regressions in user/device/nvidia setup. 3. **Image smoke** (`docker/tests/smoke.sh`) — `/wolf/wolf` and `/wolf/fake-udev` present and **ldd-clean**; `fake-udev --help` runs; the custom `gst-plugin-waylanddisplay` is present in `GST_PLUGIN_PATH` and loads via `gst-inspect-1.0 waylanddisplay`; `Xwayland` on PATH, `/opt/gow/startup-app.sh` staged, key Dockerfile-ENV vars survive cont-init. Shared helpers in `bin/tests/lib.sh` bind-mount at `/smoke-common`, mirroring the gow convention. CI wiring: `docker-build.yml`'s Build step gains `load: ${{ steps.prep.outputs.push != 'true' }}` so fork PRs still end up with a locally-tagged image for the harness. A new Smoke-test step runs after build. ### Catch2 `[WAYLAND][resolution]` tests Extends the existing `tests/platforms/linux/wayland-client.hpp` scaffolding and appends ten new TEST_CASEs tagged `[WAYLAND][resolution]`. Client-side plumbing added to `wayland-client.hpp`: - `OutputEvent` + `ToplevelConfigureEvent` types with `TSQueue`s on `WClientState` - `wl_output` listener bound in the registry callback (geometry / mode / done / scale / name / description) - `xdg_toplevel` listener bound in `w_display_create_window` - Helpers: `drain_output_events`, `drain_toplevel_configure_events`, `latest_mode`, `latest_geometry`, `w_roundtrip_n` - Forward-declarations for the legacy free-function API (test-local, keeps production header clean). Default `render_node = "software"` for CI portability. New TEST_CASEs (via `make_resolution_harness()`): 1. Output advertises configured mode to client on bind 2. Toplevel receives initial configure with window size 3. Resolution change propagates to connected client 4. Multiple resolution toggles each propagate 5. Framerate change updates `wl_output.mode.refresh` 6. Client never sees resolution larger than current output 7. Toplevel `max_size` clamps configure after resolution change 8. Rapid back-to-back resolution changes converge on the final mode 9. Idempotent same-resolution VideoInfo does not break the client 10. Keyboard input still delivers after a mid-session resize These tests exercise the same regression path as games-on-whales/gst-wayland-display#27 — covering gstreamer → Rust → Wayland → client in both repos so either side can localise a regression. ### Reviving `[WAYLAND]` under `LINK_RUST_WAYLAND=ON` Three surgical changes to make the entire `[WAYLAND]` tag compile + pass: - **Test-local forward-declarations** in `wayland-client.hpp` for the legacy free-function API (which lives in `src/core/.../wayland-display.cpp` but isn't declared in the production header). Default `render_node = "software"` for sandbox portability. - **Linker stubs** in `src/core/src/platforms/linux/virtual-display/wayland-display.cpp` for the NEW-signature `create_wayland_display(gst_element_ptr, string)` and `get_wayland_socket_name` that `libwolf_runner.so` now references, plus `= default` destructors for `WaylandMouse` / `WaylandKeyboard` / `WaylandTouchScreen` (declared in the header but previously only implemented in the `LINK_RUST_WAYLAND=OFF` impl). The stubs log a warning and return empty; the `LINK_RUST_WAYLAND=ON` path is test-only. - **Test assertion fixes**: (a) wrap `Wayland{Mouse,Keyboard}` explicitly through the underlying variant type before storing into `std::optional<std::variant<...>>` — libstdc++ 14+ no longer chains that conversion implicitly. (b) Relax the `[WAYLAND][resolution]` cases' configure-size assertions: when the client has not set `xdg_toplevel.max_size`, the compositor emits `configure(0, 0)` (xdg-shell's "client picks"), so assertions are on `wl_output.mode` dimensions + configure-arrived rather than configure width/height. The `max_size clamps` case sets `max_size` explicitly and continues to assert bounds directly. (c) `graphic_devices` `SizeIs(2)` relaxed to accept the software path (empty device list). ### Verification Built `libgstwaylanddisplay` from games-on-whales/gst-wayland-display#27 (the companion fix + Rust-level integration tests) and linked wolftests against it: ``` PKG_CONFIG_PATH=… cmake -DLINK_RUST_WAYLAND=ON -DBUILD_TESTING=ON … cmake --build . --target wolftests ./tests/wolftests '[WAYLAND]' --reporter junit # → <testsuite name="wolftests" errors="0" failures="0" tests="182" …> ``` All 12 `[WAYLAND]` cases pass. Red-green verified by temporarily re-introducing the early `return` in `wayland-display-core/src/comp/mod.rs` `apply_video_info` — 6 of 10 `[WAYLAND][resolution]` cases go red, confirming the suite catches the regression the companion PR protects against. ### Deliberate omissions - **No variant flag.** gow#321 needed `--variant fedora` for Fedora images; wolf ships only the Ubuntu 25.04 runtime stage. - **No "launch wolf for N seconds and grep logs" check.** Wolf has no `--version` / `--help`, so a launch-smoke would need a tmpfs cfg dir and a kill-timer — fragile as a layer-3 static assertion. ## Test plan - [ ] This PR's CI run — the image-smoke harness is wired into `docker-build.yml`, so the build-and-push is itself the first harness run. - [ ] Run image-smoke locally once available: `docker pull ghcr.io/games-on-whales/wolf:edge && ./bin/test-image.sh ghcr.io/games-on-whales/wolf:edge` → expect `== PASS ==`. - [ ] Run Catch2 `[WAYLAND]` locally: build wolftests with `-DLINK_RUST_WAYLAND=ON`, `./tests/wolftests '[WAYLAND]'` → expect 12 passing cases. --- <sub>🔄 This issue represents a GitHub Pull Request. It cannot be merged through Gitea due to API limitations.</sub>
bsakaguchi 2026-10-15 13:00:37 +00:00
Sign in to join this conversation.
No milestone
No project
No assignees
1 participant
Notifications
Due date
The due date is invalid or out of range. Please use the format "yyyy-mm-dd".

No due date set.

Dependencies

No dependencies set.

Reference
games-on-whales/wolf#443
No description provided.