Skip to content

A red CI job reports only its first failing test *step*, hiding the rest (the step-level twin of #616) #618

Description

@Yaraslaut

#616 removed stopOnFailure from the test presets so a red leg names every failing test rather than the first one ctest reached. The same defect exists one level up, at the step level, and #616 does not touch it: GitHub Actions skips a job's remaining steps once one fails, so a job with two or more test steps still reports only the first one that went red.

Found while checking, for #616, whether any stop-on-failure equivalent lived outside CMakePresets.json. It does not — there is no --stop-on-failure, no Catch2 --abort, and every ci.yml matrix already sets fail-fast: false — but this is the same failure mode by a different mechanism, and it is worth recording rather than leaving for whoever next reads a half-reported job.

Where it bites

Three jobs in .github/workflows/ci.yml run more than one independent test activity in sequence, with nothing marking the later ones if: always():

  • ladder-sanitizers (job at line 1430). Test (offscreen Qt platform, ladder tests only, stress excluded) (ctest --preset clang-asan -L ladder -LE stress, line 1577), then Test (the Qt transport suites, which no sanitizer leg ran) (line 1602). These are disjoint test sets. A ladder failure means the Qt transport suites — the only place any leg runs them under a sanitizer, per that step's own comment — are never run, and the log cannot distinguish "the Qt suites are fine" from "the Qt suites were not attempted".
  • ladder-tests (job at line 981). Test (offscreen Qt platform, ladder tests only, stress excluded) (line 1295), then Run the scenario corpus against the built servers (line 1328). A ctest failure skips the wire-level scenario corpus entirely.
  • linux-all-features (job at line 1689). Test (offscreen Qt platform) (line 1850), then Verify the fuzz replay covered the committed reproducers (line 1858). The second step is a guard against the fuzz replay silently matching nothing — a guard that is itself skipped whenever the test step it follows goes red.

linux-coverage (line 559) has the same shape between its ctest step and the coverage checks after it, though there the later steps genuinely depend on the earlier one's profile output, so it is the weakest of the four.

Verification status

Inferred from reading ci.yml at 1e5d0ade (this is the shape of the file at a020e69c plus #616's preset change, which does not touch ci.yml), not reproduced by making a leg fail in CI. What is verified:

  • The step lists above are real: the steps named exist at those lines, in that order, and none of the later ones carries if: always() or continue-on-error.
  • The matrix-level equivalent is not a problem — all four strategy: blocks in ci.yml set fail-fast: false:
$ grep -n "strategy:" -A1 .github/workflows/ci.yml
103:    strategy:
104-      fail-fast: false
--
230:    strategy:
231-      fail-fast: false
--
401:    strategy:
402-      fail-fast: false
--
1701:    strategy:
1702-      fail-fast: false

What is not verified: I did not push a branch that fails ladder-sanitizers' first test step to observe the second being skipped. That claim rests on GitHub Actions' documented default step behaviour, not on an observed run in this repository.

What would change the verdict

  • Close it if a run is produced in which a job's first test step fails and a later test step in the same job still executes and reports — that would mean the default does not apply here as described.
  • Close it as not worth fixing if someone argues the ordering is deliberate: there is a real counter-argument, that running the Qt transport suites after the ladder suites have already gone red costs sanitizer-leg minutes for a job that will fail regardless. ci: every ctest preset sets stopOnFailure, so a leg with six failures reports one — and which one is a race #616's own reasoning cuts the other way (the slowest leg in the matrix, Valgrind, already reports in full), but that reasoning was argued for ctest cases within one step and has not been argued for whole steps. This is the decision the fix needs, and it should be made before the if: always() sprinkling, not after.
  • Re-open if it is fixed and a later job grows a second test step without if: always().

Not folded into #616

.github/workflows/ci.yml is queued to be touched by #605 next sweep, and #616's change needed no workflow edit at all, so #617 leaves that file untouched on purpose.

Related

Activity

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Metadata

Metadata

Assignees

No one assigned

    Labels

    area: ciSubsystem: cibugSomething isn't workingtriage: validWell-framed; implement as written

    Type

    No type

    Projects

    No projects

      Milestone

      No milestone

      Relationships

      None yet

      Development

      No branches or pull requests

      Issue actions