Skip to content

Declare selftest fixture tiers so packaged fixtures stop going amber - #1155

Open
Alexandre Zollinger Chohfi (azchohfi) wants to merge 1 commit into
mainfrom
azchohfi-selftest-skip-reporting-tiers
Open

Declare selftest fixture tiers so packaged fixtures stop going amber#1155
Alexandre Zollinger Chohfi (azchohfi) wants to merge 1 commit into
mainfrom
azchohfi-selftest-skip-reporting-tiers

Conversation

@azchohfi

Copy link
Copy Markdown
Collaborator

Fixes #1154.

The problem

Packaged_* fixtures share one corpus with the unpackaged tier and self-skip there, so every unpackaged run left three permanent entries in SkippedFixtures_AreReported's amber inventory — a channel whose value depends on being rare — growing by one line per packaged fixture added.

Those fixtures can never assert unpackaged: the gate keys off the entry assembly, so the condition is structural. A skip is a per-run observation; this is a fixed property of the fixture, and restating it every run was the wrong shape.

The approach

Rather than the issue's recommended option B (a machine-readable category on each # SKIP directive), applicability is declared on the fixture, once:

["Packaged_IdentityGuard"] = SelfTestTier.Packaged,

Both --self-test and --list-fixtures are fed from SelfTestFixtureRegistry.FixturesForCurrentTier, so a fixture this host cannot run is not selected, emits no TAP, and gets no test case.

This is not the issue's rejected option D. The source corpus stays shared and identical; only the runtime selection differs, declared as data in one place. The visible cost is that --list-fixtures becomes tier-dependent — which is exactly the fact being modelled.

What it doesn't touch: SkippedFixtures_AreReported needed no edit — with the fixtures unselected its amber clears on its own. The # SKIP taxonomy, Harness.Skip, TryParseSkipDirective, FixtureStatus and every existing skip test are unchanged.

The runtime gate stays, and is not redundant. Selection cannot observe identity — it keys off which binary is running. RequirePackagedTier remains what catches the packaged host launched without identity, which IdentityDependentFixtures_Actually_Asserted turns into a red.

Keeping an absence honest

Fixing something by removal is the risk here: "no amber" is what you get whether the filter works or whether somebody deleted the packaged corpus. So the host names what it excluded, after # Total failures: and with prefixes distinct from the skip trailers:

# Total not-applicable fixtures: 3
# Not applicable fixture list: Packaged_IdentityGuard, Packaged_SettingsStoreRoundTrip, …

The two shims then assert opposite things:

shim assertion what it catches
SelfTestBatch.NotApplicableFixtures_AreExcludedFromThisTier list non-empty, and none of those names reached discovery or the run filter removed, declaration emptied, or the packaged fixtures deleted
PackagedSelfTestBatch.EveryFixture_IsApplicableToThePackagedTier count is zero the tier probe mis-evaluating there, silently dropping the only fixtures that tier exists to run

A missing trailer is deliberately never read as a count of zero — that would let a host which stopped reporting satisfy the packaged assertion by silence.

Verification

Mutation-checked, not just green. Emptying TierRequirements reproduces the issue's reported output verbatim — all three Packaged_* back in the amber inventory — and reddens NotApplicableFixtures_AreExcludedFromThisTier with cause (a). So the declaration is demonstrably what removes the amber, and the new test demonstrably reddens when it goes away.

  • dotnet test tests/Reactor.SelfTestsSkippedFixtures_AreReported no longer lists any Packaged_*; 3 fewer Fixture cases; 9 new TierApplicabilityTests pass.
  • dotnet test tests/Reactor.PackagedTests under real MSIX identity — 7/7, zero exclusions reported; 47/47 headless.
  • Release build clean for both touched test projects.
  • Both hosts cross-checked: unpackaged lists 1472 with 3 excluded, packaged lists 1475 with 0 excluded (1472 + 3 = 1475).

One unrelated pre-existing failure on my machine: Issue487_ScrollViewOffsetRestoredAfterRunMutation. CI is green at the base commit (fceaf52), and it reproduces under --filter Issue487, where this change is provably inert — the filtered fixture set is byte-identical either way. Machine-specific (non-interactive desktop), not this PR.

Docs

TESTING.md §2 and §3, AGENTS.md, and the PackagedIdentityFixtures / RequirePackagedTier doc comments now say a packaged fixture needs two declarations and explain why neither replaces the other. probe-aot-skips.ps1 drops # lines for the same reason the two shim parsers do.

Known trade-off

A fixture wrongly declared packaged-only silently leaves the unpackaged run. It still runs in the packaged CI job, so coverage moves rather than disappears, and the trailer names it on every run. The reverse mistake — a new packaged fixture nobody declared — still self-skips and still goes amber, which is the "you forgot to declare it" signal.

`Packaged_*` fixtures shared one corpus with the unpackaged tier and
self-skipped there, so every unpackaged run left three permanent entries in
`SkippedFixtures_AreReported`'s amber inventory — a channel whose value depends
on being rare — growing by one line per packaged fixture added. Those fixtures
can never assert unpackaged: the gate keys off the entry assembly, so the
condition is structural, and a skip is the wrong shape for it. A skip is a
per-run observation; this is a fixed property of the fixture.

Declare the requirement instead. `SelfTestFixtureRegistry.TierRequirements`
maps the three fixtures to `SelfTestTier.Packaged`, and both `--self-test` and
`--list-fixtures` are fed from `FixturesForCurrentTier`, so a fixture the host
cannot run is not selected, emits no TAP, and gets no test case. The source
corpus stays shared and identical; only the runtime selection differs, declared
as data in one place. `SkippedFixtures_AreReported` needed no edit — with the
fixtures unselected its amber clears on its own — and the `# SKIP` taxonomy,
`Harness.Skip` and every existing skip test are untouched.

The runtime gate stays and is not redundant. Selection cannot observe identity
(it keys off which binary is running), so `RequirePackagedTier` remains what
catches the *packaged* host launched without identity, which
`IdentityDependentFixtures_Actually_Asserted` turns into a red.

Fixing something by removal is the risk here: "no amber" is what you get
whether the filter works or whether somebody deleted the packaged corpus. So
the host names what it excluded, after `# Total failures:` and with prefixes
distinct from the skip trailers, and the two shims assert opposite things —
the unpackaged one that the list is non-empty and that none of those names
reached discovery or the run, the packaged one that it is *zero*, which is what
catches the tier probe mis-evaluating there and silently dropping the only
fixtures that tier exists to run. A missing trailer is deliberately never read
as a count of zero, or a host that stopped reporting would satisfy the packaged
assertion by silence.

Verified by mutation: emptying `TierRequirements` reproduces the issue's
reported output verbatim (all three `Packaged_*` back in the amber inventory)
and reddens `NotApplicableFixtures_AreExcludedFromThisTier`. The packaged tier
passes under real MSIX identity with zero exclusions reported.

Fixes #1154

Co-authored-by: Copilot App <223556219+Copilot@users.noreply.github.com>
Copilot-Session: 885f2d1f-9615-477f-8a11-3014730614eb
@github-actions

Copy link
Copy Markdown
Contributor

📦 Build metrics

Artifact sizes for 55307f1 vs the base branch (fceaf52).

Packages (compressed .nupkg)

Artifact base PR Δ
Microsoft.UI.Reactor.nupkg 1.63 MB 1.63 MB -5 B (0.00%)
Microsoft.UI.Reactor.Advanced.nupkg 487.4 KB 487.4 KB -6 B (0.00%)
Microsoft.UI.Reactor.Devtools.nupkg 283.2 KB 283.2 KB -4 B (0.00%)

Assemblies in Microsoft.UI.Reactor

Artifact base PR Δ
Reactor.Analyzers.dll 360.5 KB 360.5 KB +0 B (0.00%)
Reactor.dll 2.41 MB 2.41 MB +0 B (0.00%)
Reactor.Localization.Generator.dll 16.0 KB 16.0 KB +0 B (0.00%)
Reactor.Wrappers.Abstractions.dll 10.5 KB 10.5 KB +0 B (0.00%)
Reactor.Wrappers.Generator.dll 99.5 KB 99.5 KB +0 B (0.00%)

Assemblies in Microsoft.UI.Reactor.Advanced

Artifact base PR Δ
Reactor.Advanced.dll 1021.5 KB 1021.5 KB +0 B (0.00%)

Assemblies in Microsoft.UI.Reactor.Devtools

Artifact base PR Δ
Microsoft.UI.Reactor.Devtools.dll 784.5 KB 784.5 KB +0 B (0.00%)

No size change beyond the noise floor. ✅

✅ smaller / ⚠️ larger / ≈ within noise. Sizes come from a Release dotnet pack on the CI runner: packages are the compressed .nupkg download size, assemblies the uncompressed DLL inside it.
workflow run.

$"truncated between the two trailer lines, which would make every check below reason " +
$"about a partial list.\nNamed: {string.Join(", ", report.Names)}");

Assert.IsTrue(report.Count.Value > 0,
@github-actions

Copy link
Copy Markdown
Contributor

🧪 Merged coverage

Coverage for 55307f1 vs the base branch (fceaf52) — unit + selftest merged.

Metric base PR Δ
Line 85.66% 85.66% 0.00 pp
Branch 76.87% (904/1176) 76.87% (904/1176) 0.00 pp

No coverage change beyond the noise floor. ✅

✅ higher / ⚠️ lower / ≈ within noise. Δ is in percentage points; coverage is unit + selftest merged (Debug x64) on the CI runner. Cobertura reports attached to the workflow run as artifacts.

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.

Selftest skip reporting can't tell "broken" from "not applicable to this tier", so Packaged_* fixtures go amber on every unpackaged run

1 participant