Skip to content

test(gl): fail instead of skipping when the GPU mixer breaks - #917

Merged
srperens merged 2 commits into
Eyevinn:mainfrom
wagenet:wagenet/test-scaffolding
Oct 2, 2026
Merged

srperens merged 2 commits into
Eyevinn:mainfrom
wagenet:wagenet/test-scaffolding

Conversation

@wagenet

@wagenet wagenet commented Sep 29, 2026 •

Copy link
Copy Markdown
Contributor

Opened by Claude (AI), on Peter Wagenet's account.

Closes three ways the GL tests pass green without testing anything.

  • GPU mixer build or start failure was a skip. vision_mixer_fx_test printed SKIP: could not build GPU pipeline and returned, even though the GL probe had just shown the environment renders, and even under STROM_REQUIRE_GL=1. So on the macOS job, the one that renders, a GPU vision mixer that stopped building passed. Both tests now expect the build and the start.
  • Missing GL elements were folded into "no GL context". Linux skips that case legitimately (headless, no context), so a dropped gstreamer1.0-gl package would go unnoticed there. vision_mixer_fx_test and shader_validation_test now check the elements separately, through a new common::gl_elements_available. It fails under STROM_REQUIRE_GL, since a platform that must render cannot do it without them, and otherwise defers to common::require_or_skip, so a missing element fails under STROM_REQUIRE_GST_PLUGINS like every other. The no-context case still skips unless STROM_REQUIRE_GL is set.
  • Shared block ID. Both fx tests used "vmfx". The vision mixer's overlay state is process-global and keyed by block ID, and tests in one binary run concurrently. The letterbox test now uses "vmfx-letterbox".

Tests run (macOS, --features efp,nvidia, head 7d9968c)

  • STROM_REQUIRE_GST_PLUGINS=1 STROM_REQUIRE_GL=1 cargo test --test vision_mixer_fx_test --test shader_validation_test: 4 passed.
  • Missing GL elements, with the GL plugin hidden from GStreamer (a plugin path without libgstopengl), --no-fail-fast --nocapture:
    • STROM_REQUIRE_GST_PLUGINS=1 alone, or STROM_REQUIRE_GL=1 alone: all 4 tests fail, naming the missing elements.
    • Neither set: all 4 print SKIP: required GStreamer elements missing and pass, as on a developer machine without GL.
  • cargo clippy --all-targets --features efp,nvidia -- -D warnings: clean.

Revert check, run on the previous head aea811e (before the rebase; the GPU build/start expects are unchanged since): made the "gpu" arm of select_backend (vision_mixer/elements.rs) always return its error.

  • With this branch: both fx tests fail.
  • With the upstream test files: both print SKIP: could not build GPU pipeline and pass.

Fork CI with macOS dispatched, on 7d9968c (run). It does not show as a check here:

  • macOS: passed, with STROM_REQUIRE_GL=1 and STROM_REQUIRE_GST_PLUGINS=1. vision_mixer_fx_test took 15.4 s and shader_validation_test about 2.6 s, so both rendered.
  • Windows, on the earlier head aea811e (run): "Run tests" passed with STROM_REQUIRE_GST_PLUGINS=1, so the MSI does install the GL elements. Both GL binaries stopped at the no-context skip, as before this PR. Not rerun on this head.

Linux, from the same run's Check (Linux) job: both GL binaries pass with STROM_REQUIRE_GST_PLUGINS=1 in 0.03 s. So the GL elements are installed, and the tests stop at the no-context skip, as before.

Not run:

  • The rest of the suite locally, since only test files change.

Overlap

#809, #806 and #803 also edit vision_mixer_fx_test.rs, #809 heavily. Whichever lands second needs a small rebase.

🤖 Generated with Claude Code

@wagenet
wagenet force-pushed the wagenet/test-scaffolding branch from 560b54e to aea811e Compare September 29, 2026 20:37
@wagenet
wagenet marked this pull request as ready for review September 29, 2026 21:56
@srperens srperens mentioned this pull request Sep 30, 2026

@srperens srperens left a comment

Copy link
Copy Markdown
Collaborator

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Verdict: Comment. The three changes are correct and each closes a real false-green. There are two gaps. The element checks re-implement a helper that landed on main today. And the one platform where the new expects can fire has not run this head in this repo's CI.

Requested changes

  1. Rebase onto main and route the missing-element case through backend/tests/common/mod.rs. Use common::missing_elements(&[...]), and if STROM_REQUIRE_GL is set, fail first. Then return common::require_or_skip(&missing). 34008fe (#912) added that helper so that "every skip on a missing element goes through here, so none can quietly opt out". This PR adds two more hand-rolled copies of the same STROM_REQUIRE_GST_PLUGINS panic: backend/tests/shader_validation_test.rs:110 — fn gl_elements_available() -> bool { and backend/tests/vision_mixer_fx_test.rs:71 — let missing: Vec<&str> = ["glvideomixerelement", "glshader", "gltestsrc"]. STROM_REQUIRE_GL is the only part the helper lacks. The PR's merge base (a8ace5f) predates #912, so it could not have used it.

Needs the maintainer

  • Add the ci:macos label. On Linux both GL binaries stop at the no-context skip (the body says so, and I agree: the expects sit after gl_available_or_required()). So the build and start expects at backend/tests/vision_mixer_fx_test.rs:156 — .expect("GPU vision mixer pipeline builds"); and :423 have never executed in this repo's CI. The fork run in the body is not a check on this PR.

Claims

Claim Verdict Evidence
A GPU build/start failure used to skip even under STROM_REQUIRE_GL CONFIRMED The removed arms eprintln!("SKIP: could not build GPU pipeline ({})", e); return; ran after the GL probe had already returned true.
Missing GL elements were folded into "no context" CONFIRMED The removed find(...).is_none() ... return false sat inside gl_environment_available, and the Linux job skips on that function's false result.
Overlay state is process-global and keyed by block ID CONFIRMED backend/src/blocks/builtin/vision_mixer/overlay.rs:27 — /// Global registry of vision mixer overlay states, keyed by block instance ID., backed by a static INSTANCE: OnceLock<...>. Two tests sharing "vmfx" in one binary could therefore collide.
The new failures fire on revert UNVERIFIED These are the author's macOS runs only. This repo has no macOS run at aea811e.

Diagnosis: This is the right layer. Each change turns a silent return into either a panic or an expect, and the no-context skip that headless Linux legitimately needs is kept. Coverage is BOUNDED to these two files. ElementFactory::find proves that an element is registered, not that it loads. In both files a gl_environment_available() render probe follows the element check and proves loading, so that is not a gap here.

Radius: LOCAL. The diff touches test files only.

Overlaps: #809, #806 and #803 also edit backend/tests/vision_mixer_fx_test.rs. Those are textual conflicts; none of them settles a design question here. The body already names all three.

Tests & CI: At aea811e, Check (Linux), both Linux builds, WASM and API Contract are green, and Build (macOS) and Build (Windows) show skipping. I did not fetch the Linux job log for the GL binaries' timing. The 0.04–0.05 s figure is the author's.

Confidence: HIGH

wagenet and others added 2 commits September 30, 2026 21:42
vision_mixer_fx_test printed SKIP and passed when the GPU vision mixer
failed to build or start, even after the GL probe had proven the
environment renders and even under STROM_REQUIRE_GL. A GPU mixer that
stopped building passed green on the macOS job. Those paths now fail.

Missing GL elements were folded into "no GL context", which the Linux
jobs treat as a legitimate skip. Every CI job installs the GL plugins,
so both GL test files now fail on a missing GL element under
STROM_REQUIRE_GST_PLUGINS, like every other missing element, and also
under STROM_REQUIRE_GL, since a platform that must render cannot do it
without them.

The two fx tests shared block ID "vmfx". The vision mixer's overlay
state is process-global and keyed by block ID, and the tests run
concurrently, so the letterbox test now uses its own ID.

Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
Both GL test files hand-rolled the STROM_REQUIRE_GST_PLUGINS check that
common::require_or_skip already owns. common::gl_elements_available adds
the one thing that helper lacks, failing under STROM_REQUIRE_GL too, and
both files now call it.

Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
@wagenet
wagenet force-pushed the wagenet/test-scaffolding branch from aea811e to 7d9968c Compare October 1, 2026 05:06
@wagenet

wagenet commented Oct 1, 2026

Copy link
Copy Markdown
Contributor Author

Claude (AI) here, replying on Peter Wagenet's account.

Requested change: done in 7d9968c, after rebasing onto main. common::gl_elements_available(required) in backend/tests/common/mod.rs calls missing_elements and fails if any are missing while STROM_REQUIRE_GL is set. It then returns require_or_skip(&missing). Both GL test files call it, and their hand-rolled copies are gone. I put it in common so the STROM_REQUIRE_GL check is not repeated in each file.

With the GL plugin hidden, all 4 tests fail under either variable and skip with neither set. Details are in the PR body.

ci:macos: I can't apply the label from this account. A fork dispatch on 7d9968c ran Build (macOS) with STROM_REQUIRE_GL=1 and passed (run). vision_mixer_fx_test took 15.4 s and shader_validation_test 2.6 s, so both rendered and the build/start expects executed. It still isn't a check on this PR, so the label is still needed.

The first macOS attempt failed earlier in the run, in liveaudiorouter_test::a_late_input_reaches_a_mixer_that_locked_its_rate_on_the_router (audiotestsrc stopped with not-linked). This PR doesn't touch that test. It passed on rerun.

@srperens srperens left a comment

Copy link
Copy Markdown
Collaborator

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Supersedes my review at aea811e (Comment). Re-reviewed at 7d9968c, which is a rebase onto main plus one new commit. Against main the diff is now three test files. The verdict stays at Comment, for the macOS run alone.

Verdict: Comment. The requested change is done, and done correctly. The new expects can fire on only one platform, and that platform still has no run of this head in this repo.

Needs the maintainer

  • Add the ci:macos label. The only CI run at 7d9968c (36818218728) shows Build (macOS) and Build (Windows) as skipping. On Linux both GL binaries finish in about 0.05 s. That is consistent with the no-context skip, so backend/tests/vision_mixer_fx_test.rs:142 — .expect("GPU vision mixer pipeline builds"); and :409 have still never executed here. The alternative is to merge on Linux green and let the macOS build on main be the first real run. That is a legitimate call, but if the GPU mixer is broken on macOS today, that build will go red after the merge rather than before it.

Claims

Claim Verdict Evidence
Build/start failures used to skip; missing elements were folded into "no context"; block IDs collided on global overlay state CONFIRMED CONFIRMED in my review of 2026-09-30 at aea811e. The rebase did not change these hunks' substance.
Missing GL elements now go through the shared skip gate CONFIRMED backend/tests/common/mod.rs:48 — pub fn gl_elements_available(required: &[&str]) -> bool {. It asserts under STROM_REQUIRE_GL, then returns require_or_skip(&missing), so STROM_REQUIRE_GST_PLUGINS still applies. Both hand-rolled copies are gone. backend/tests/vision_mixer_fx_test.rs:73 — if !common::gl_elements_available(&["glvideomixerelement", "glshader", "gltestsrc"]) {. Both files include it as pub mod common;, which is the form the module's header asks for, so it does not trip dead-code warnings.
The new failures fire on revert UNVERIFIED Only on the author's runs. This repo has no macOS run at 7d9968c.

Radius: LOCAL. The changes are test files plus one additive helper. The helper has no callers outside these two binaries.

Overlaps: #809, #806 and #803 still edit backend/tests/vision_mixer_fx_test.rs. These are textual conflicts only. No open PR touches backend/tests/common/mod.rs.

Tests & CI: At 7d9968c (run 36818218728), Check (Linux), both Linux builds, WASM and API Contract are green. Job 110227881429 shows all four GL tests ok, at Linux-skip timings.

Confidence: HIGH

srperens added a commit to wagenet/strom that referenced this pull request Oct 2, 2026
…itch

This branch now uses common::gl_elements_available from Eyevinn#917. Once Eyevinn#917
is on main, its commits drop out of this PR's diff.
srperens added a commit to wagenet/strom that referenced this pull request Oct 2, 2026
… helper

The resize tests had their own copy of the GL skip check, which folded
missing GL elements into "no GL context". Linux CI skips that case, so a
dropped GL package would turn all eight guards green without running them.
Check the elements with common::gl_elements_available from Eyevinn#917 first, and
keep the context probe for the legitimate headless skip.

Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
@srperens

srperens commented Oct 2, 2026

Copy link
Copy Markdown
Collaborator

Ran on macOS (aarch64, GStreamer 1.28.6) with STROM_REQUIRE_GL=1 STROM_REQUIRE_GST_PLUGINS=1, this head merged with current main:

Run shader_validation_test vision_mixer_fx_test
This PR 2/2 ok 2/2 ok, 4.96 s (renders, no SKIP)
This PR, GPU mixer factory name broken in elements.rs – 2/2 FAILED on the build expect (:142, :409)
main's test file, same broken mixer – 2/2 ok in 0.14 s (silent skip)

The last row is the hole this closes. Not run: clippy and the full suite. The break was local only and reverted.

Merging. #894 now uses common::gl_elements_available from here.

Claude (AI), on behalf of @srperens.

@srperens
srperens merged commit f25f24f into Eyevinn:main Oct 2, 2026
9 checks passed
srperens added a commit that referenced this pull request Oct 2, 2026
* fix(vision mixer): keep a source's new shape when it changes size

The GPU mixer's per-input glshader (fx_look, fx_take) takes its output
size from the first entry of downstream's caps. After the first
negotiation the compositor answers with the size it already has, so a
source that changes size is stretched to its first shape: a camera
switched to portrait, or a new publisher on a reused WHIP slot. The
mixer never sees a caps change and never re-fits the aspect.

Open width and height in the caps answer on each filter's peer pad so
the filter stays at its input size.

Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>

* fix(vision mixer): re-fit an input only once its new caps are stored

The caps probe queues a geometry refresh on the main loop, which runs on
its own thread. A pad stores caps only after its probes return, so the
refresh could run first, read the old size, find nothing changed and
leave the input in its old shape. Requeue the refresh until the pad
holds the caps that triggered it.

Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>

* fix(vision mixer): re-fit from stored caps and the configured PGM size

Refresh an input's geometry from the pad's notify::caps, which fires
after the pad stores new caps, instead of a caps event probe that fires
before. A refresh queued from the probe could read the old size when the
streaming thread was held up before the store, and the source stayed
stretched until its next shape change. This replaces the bounded requeue.

Fall back to the block's configured PGM size, not 1920x1080, when the
mixer output has not negotiated yet. The first refresh runs before it
has, so a source present at start was fitted to a 1080p canvas on any
other PGM size and stayed misplaced.

Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>

* fix(vision mixer): hold a re-fit until a take or FTB is over

Re-fitting an input clears the pad's control bindings, so a source
that changed size during a fade or wipe ended the transition as a cut.
The GPU mixer now reaches that path on every resize, because the effect
shaders pass the new size through.

The geometry refresh now leaves an animating compositor alone, marks
the layout pending, and runs again after the last keyframe. FTB off
fits the program pads to their sources' current shapes before they
fade back in, so a source that changed shape during FTB no longer
comes back stretched.

Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>

* fix(vision mixer): let Fade to Black play out on a slow mixer

FTB wiped its alpha keyframes on a wall-clock timer, duration + 100 ms.
The keyframes are in the mixer's stream time, so a mixer running slower
than real time had its fade wiped part-way and stayed there: never
reaching black, or coming back dimmed. The same timer wiped the fade-in
of an FTB off pressed during the FTB-on fade. The cleanup now waits
until the mixer's position passes the fade's end, and skips a control
source a later FTB or take has reprogrammed.

FTB off also re-applies a PiP source's crop, which is in pixels of the
source and was left sized for a source that changed shape during FTB.

The fade and FTB tests now time their checks by the mixer's clock
instead of the wall clock.

Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>

* test(gl): fail instead of skipping when the GPU mixer breaks

vision_mixer_fx_test printed SKIP and passed when the GPU vision mixer
failed to build or start, even after the GL probe had proven the
environment renders and even under STROM_REQUIRE_GL. A GPU mixer that
stopped building passed green on the macOS job. Those paths now fail.

Missing GL elements were folded into "no GL context", which the Linux
jobs treat as a legitimate skip. Every CI job installs the GL plugins,
so both GL test files now fail on a missing GL element under
STROM_REQUIRE_GST_PLUGINS, like every other missing element, and also
under STROM_REQUIRE_GL, since a platform that must render cannot do it
without them.

The two fx tests shared block ID "vmfx". The vision mixer's overlay
state is process-global and keyed by block ID, and the tests run
concurrently, so the letterbox test now uses its own ID.

Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>

* test(gl): route missing GL elements through the shared test helper

Both GL test files hand-rolled the STROM_REQUIRE_GST_PLUGINS check that
common::require_or_skip already owns. common::gl_elements_available adds
the one thing that helper lacks, failing under STROM_REQUIRE_GL too, and
both files now call it.

Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>

* test(vision mixer): pass take indices through a helper that fits either signature

#806 changes trigger_transition's input indices from usize to
Option<usize>. idx() converts into whichever the method takes, so these
tests compile whether #806 lands before or after this PR.

Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>

* test(vision mixer): route missing GL elements through the shared test helper

The resize tests had their own copy of the GL skip check, which folded
missing GL elements into "no GL context". Linux CI skips that case, so a
dropped GL package would turn all eight guards green without running them.
Check the elements with common::gl_elements_available from #917 first, and
keep the context probe for the legitimate headless skip.

Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>

---------

Co-authored-by: Claude Opus 5.5 <noreply@anthropic.com>
Co-authored-by: Per Enstedt <per.enstedt@eyevinn.se>
@wagenet
wagenet deleted the wagenet/test-scaffolding branch October 2, 2026 15:05
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

2 participants