Skip to content

fix(ci): correct dead L0 test matrix condition in build.yml (ISD-7073) - #233

Merged
florentianayuwono merged 15 commits into
mainfrom
fix/ci-l0-test-matrix-condition-isd-5856
Oct 8, 2026
Merged

florentianayuwono merged 15 commits into
mainfrom
fix/ci-l0-test-matrix-condition-isd-5856

Conversation

@florentianayuwono

@florentianayuwono florentianayuwono commented Oct 6, 2026 •

Copy link
Copy Markdown

Overview

The L0 test step in .github/workflows/build.yml compares matrix.runtime against bare architecture names (arm64/amd64):

if: matrix.runtime == 'arm64' || matrix.runtime == 'amd64'

But matrix.runtime values are always linux-*-prefixed — the bare names only ever appear in the separate matrix.runs_on field. This mismatch means the condition never evaluates true for any matrix leg: ./dev.sh test has silently never run as part of this workflow, on any architecture, on any PR or push to main/releases/*.

Found while auditing PR #232 (ARM32 kill-switch override): a review comment flagged untested ARM32 branches, which traced back to CI never running dotnet test at all, due to this dead condition.

Enabling dotnet test for the first time surfaced two pre-existing, previously-invisible test failures:

  1. StepHostL0 Alpine-container tests failing on linux-arm64 — StepHost.CheckPlatformForAlpineContainer gates Alpine Node support on Constants.Runner.PlatformArchitecture.Equals(Constants.Architecture.X64), which is baked in at compile time, so the check always throws NotSupportedException on arm64. Upstream actions/runner's own build.yml never runs dotnet test on linux-arm64 either (its condition excludes linux-arm64/linux-arm/osx-arm64/win-arm64, testing x64 flavors only) — so this is simply a gap this fork's workflow had opened by testing an architecture upstream never does.
  2. JobExtensionL0.JobExtensionBuildStepsList failing with "Expected 5, Actual 6" (on linux-x64 too) — JobExtension.InitializeJob reads ACTIONS_RUNNER_HOOK_JOB_STARTED/_COMPLETED directly from the real OS environment to decide whether to inject extra hook steps. This fork's self-hosted CI fleet configures a job-started hook for its own lifecycle management (confirmed in raw CI logs: "A job started hook has been configured by the self-hosted runner administrator"), so the real env var leaks into the child dotnet test process and inflates the step count the test asserts on.

Fix

  • Compare against the correct matrix.runtime values.
  • Scope the L0 step to linux-x64 only, matching upstream's own tested scope — this also makes the StepHostL0 arm64 failure moot, since those tests simply never run on arm64, exactly as upstream intends.
  • Unset ACTIONS_RUNNER_HOOK_JOB_STARTED/ACTIONS_RUNNER_HOOK_JOB_COMPLETED before invoking dotnet test in the L0 step, mirroring the existing pattern already used in tics.yaml, so this fork's self-hosted job hooks don't leak into the test process.

No src/Test files are modified — both StepHostL0.cs and JobExtensionL0.cs remain byte-identical to upstream, avoiding any risk of silent reversion by the daily upstream-sync bot (patch_update_main.yml), which wholesale-overwrites src/ from upstream on every sync and only preserves the three named arch patches.

Testing

  • Locally: dotnet test --filter "FullyQualifiedName~StepHostL0|FullyQualifiedName~JobExtensionL0" with the hook env vars both set and unset, confirming the unset step reproduces and then resolves the leak.
  • This PR's own CI: build (linux-x64) now actually runs dotnet test and passes; all other legs (linux-arm64, linux-arm, linux-ppc64le, linux-s390x) pass unaffected (no test step).

Co-authored-by: Copilot 223556219+Copilot@users.noreply.github.com

florentianayuwono and others added 3 commits October 7, 2026 01:08
The 'L0' step's condition compared matrix.runtime (always 'linux-*'-
prefixed, e.g. 'linux-x64', 'linux-arm64') against bare arch names
('arm64', 'amd64') that only ever appear in the separate matrix.runs_on
field. This mismatch meant the condition never evaluated true for any
matrix leg, so ./dev.sh test has silently never run as part of this
workflow, on any architecture, on PRs or pushes.

Compared against upstream actions/runner's build.yml to confirm intent:
upstream runs L0 on every runtime except the ones that can't execute
natively on its GitHub-hosted runners (linux-arm64, linux-arm, osx-arm64,
win-arm64, since those jobs run cross-compiled on amd64 hosts). This
fork instead builds each target on matching self-hosted native hardware
(runs-on: matrix.runs_on), so linux-arm64 can safely run its own tests
directly, unlike upstream.

Fix: compare against the correct matrix.runtime values and enable L0 for
linux-x64 and linux-arm64 (native, unpatched builds). linux-arm (32-bit
armv7l, cross-targeted), ppc64le, and s390x are intentionally left
disabled for now -- they require their respective patches applied first,
and their dotnet-test behavior under cross/32-bit targeting is not yet
validated. Enabling genuine L0 coverage for those is tracked as separate
follow-up work.

Co-authored-by: Copilot <223556219+Copilot@users.noreply.github.com>
StepHost.CheckPlatformForAlpineContainer gates Alpine Node support on
Constants.Runner.PlatformArchitecture.Equals(Constants.Architecture.X64).
That value is baked in at compile time via the X64/ARM/ARM64
preprocessor symbols (set from the PackageRuntime MSBuild property),
not detected at test-runtime.

When the Test assembly is built natively on a linux-arm64 self-hosted
runner (no explicit PackageRuntime override), PlatformArchitecture
compiles to Arm64, so these three tests deterministically throw
NotSupportedException instead of exercising the Alpine-specific
behavior they were written for. This was previously invisible because
a dead matrix condition in build.yml meant the L0 test step never
actually ran on the linux-arm64 leg.

Gate the three Alpine-container tests with #if X64 so they only
compile/run against X64-targeted Test assembly builds, matching the
production code's own intentional restriction.

Co-authored-by: Copilot <223556219+Copilot@users.noreply.github.com>
JobExtension.InitializeJob reads ACTIONS_RUNNER_HOOK_JOB_STARTED and
ACTIONS_RUNNER_HOOK_JOB_COMPLETED directly from the process
environment to decide whether to inject extra job-hook steps into the
returned step list. JobExtensionL0's tests never clear or mock these
variables, implicitly assuming they're always unset.

That assumption doesn't hold on this fork's self-hosted CI runners,
which configure a job-started hook for their own lifecycle management
(confirmed in the raw CI logs: "A job started hook has been
configured by the self-hosted runner administrator"). Since these are
real, process-level environment variables, they're inherited by the
child dotnet test process and silently add one extra step to
preJobSteps, which is why JobExtensionBuildStepsList failed with
"Expected 5, Actual 6" identically on both the linux-x64 and
linux-arm64 legs of #233's CI run, while never reproducing in a clean
local environment without the hook configured.

Capture and clear both hook variables in the constructor (xUnit
creates a new instance per test) and restore the original values in
Dispose(), following the same env-var isolation pattern already used
for the ARM32 kill-switch override tests.

Co-authored-by: Copilot <223556219+Copilot@users.noreply.github.com>

Copilot AI left a comment

Copy link
Copy Markdown

Choose a reason for hiding this comment

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

Copilot review overview

🟢 Approval recommended

The reviewed changes are complete; only a minor comment-wording nit remains.

Review effort: Lite
Findings: 1 Low severity

Open (1)
What changed in this PR

Fixes the inactive L0 test condition and makes newly enabled tests reliable on native CI architectures.

Changes:

  • Enables L0 tests for linux-x64 and linux-arm64.
  • Restricts Alpine tests to X64 builds.
  • Isolates job-hook environment variables during tests.
File Summary
src/​Test/​L0/​Worker/​StepHostL0.cs Gates Alpine-specific tests to X64 builds.
src/​Test/​L0/​Worker/​JobExtensionL0.cs Prevents ambient job-hook variables from affecting tests.
.github/​workflows/​build.yml Corrects the L0 matrix condition.

💡 Add a code-review agent skill or configure MCP servers for context-aware, tailored reviews. Learn more in the docs.

Comment thread .github/workflows/build.yml Outdated
Comment thread .github/workflows/build.yml Outdated
@florentianayuwono
florentianayuwono marked this pull request as ready for review October 6, 2026 18:27
@florentianayuwono florentianayuwono changed the title fix(ci): correct dead L0 test matrix condition in build.yml fix(ci): correct dead L0 test matrix condition in build.yml (ISD-7073) Oct 6, 2026
florentianayuwono and others added 11 commits October 7, 2026 14:44
Upstream actions/runner's own L0 condition excludes linux-arm64 (and
other non-x64 targets) from running dotnet test; this fork's matrix
condition fix should mirror that intent rather than opportunistically
running tests on linux-arm64 as well. Scoping to linux-x64 only avoids
exercising test-suite bugs that only manifest on non-x64 builds,
without requiring direct modifications to upstream-synced test files
that would be at risk of being silently reverted by the daily
patch_update_main.yml upstream sync.

Co-authored-by: Copilot <223556219+Copilot@users.noreply.github.com>
…tensionL0

Replaces the JobExtensionL0 IDisposable env-isolation fix with a build.yml-level
workaround, mirroring the existing pattern already used in tics.yaml. The
self-hosted runner's ACTIONS_RUNNER_HOOK_JOB_STARTED/_COMPLETED hooks (configured
by the fleet's runner-provisioning infra, not this repo) leak into the dotnet
test child process and inflate JobExtensionBuildStepsList's step count. Unsetting
both vars before invoking dev.sh test avoids the leak without modifying the test
file itself, keeping JobExtensionL0.cs byte-identical to upstream and removing
it from the upstream-sync overwrite risk.

Co-authored-by: Copilot <223556219+Copilot@users.noreply.github.com>
Upstream actions/runner never runs dotnet test on linux-arm64 (its condition
excludes linux-arm64, linux-arm, osx-arm64, and win-arm64, testing only x64
flavors). This fork's build.yml previously added linux-arm64 to the tested
runtimes beyond upstream's own scope, which is what exposed the
StepHostL0 Alpine-container test failures (compile-time X64/ARM64
architecture baking via Constants.Runner.PlatformArchitecture never
being exercised upstream on arm64).

Restricting back to linux-x64 only realigns with upstream's actual tested
scope and makes the StepHostL0 #if X64 gating fix unnecessary, so it's been
reverted. Both JobExtensionL0.cs and StepHostL0.cs are now byte-identical to
upstream again, removing any src/Test divergence that would otherwise be at
risk of silent reversion by the daily upstream-sync bot.

Co-authored-by: Copilot <223556219+Copilot@users.noreply.github.com>
Comment thread .github/workflows/build.yml
@florentianayuwono
florentianayuwono merged commit 7aaecbb into main Oct 8, 2026
8 checks passed
@florentianayuwono
florentianayuwono deleted the fix/ci-l0-test-matrix-condition-isd-5856 branch October 8, 2026 10:20
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.

3 participants