Skip to content

Fix net472 tool tests failing on System.Collections.Immutable bind - #732

Merged
wasabii merged 4 commits into
mainfrom
fix/importer-net472-immutable
Aug 7, 2026
Merged

Fix net472 tool tests failing on System.Collections.Immutable bind#732
wasabii merged 4 commits into
mainfrom
fix/importer-net472-immutable

Conversation

@wasabii

@wasabii wasabii commented Aug 5, 2026

Copy link
Copy Markdown
Contributor

Fixes the IKVM.Tools.Importer.Tests:net472:win-x64 failure that has been red on main since at least July, and is one of the two deterministic failures blocking #727 and #730.

Cause

Every row fails at:

Could not load file or assembly 'System.Collections.Immutable, Version=10.0.0.0'
 ---> ... 'Version=8.0.0.0'
   at IKVM.Tools.Importer.ImportOptions..ctor()

The problem is in the SDK's .NET Framework test host, not in anything we ship. testhost.net472.exe.config in SDK 10.0.302 contains:

<assemblyIdentity name="System.Collections.Immutable" publicKeyToken="b03f5f7f11d50a3a" culture="neutral" />
<bindingRedirect oldVersion="1.0.0.0-10.0.0.0" newVersion="10.0.0.0" />

and the host directory ships System.Collections.Immutable 10.0.0.0.

So IKVM.CoreLib asks for 8.0.0.0, the host redirects that up to 10.0.0.0, the loader finds the 8.0.0.0 copy sitting beside the tests, and the bind fails on major version. That accounts for the otherwise baffling 10.0.0.0 → 8.0.0.0 pair in the exception.

This was confirmed by turning on Fusion bind logging in CI (#728), which named IKVM.CoreLib as the requester and showed the bind resolving against a VSTest-generated temp config rather than the test assembly's own app.config — which is why the shipped redirect looked correct but was never the one applied.

Fix

Bump System.Collections.Immutable 8.0.0 → 10.0.10 in IKVM.Tools.Importer.Tests and IKVM.Tools.Exporter.Tests, so the assembly beside the tests is the one the host's redirect points at.

What is deliberately not changed

The pins in IKVM.deps.targets, IKVM.CoreLib, ikvmc, ikvmstub and the SDK targets are left alone.

ikvmc ships as a standalone executable with its own config and never sees the test host's redirect, so this is a test environment problem rather than a product one. The pins in IKVM.NET.Sdk.targets and IKVM.MSBuild/buildTransitive/ reach consumers, and changing those to satisfy a test-host quirk would take on real risk for no gain.

The trade-off is that these tests now run against a different System.Collections.Immutable than production ships. That is a small loss of fidelity, but the alternative changes what users get.

Verification

Restore is clean — no NU1605, which matters because it is WarningsAsErrors in this repo — and net472 resolves to System.Collections.Immutable/10.0.10.

Not verified by a local test run: the net472 build stops earlier on NETSDK1094 from ikvmstub wanting a runtime identifier for ReadyToRun. That is unrelated and already present on main. CI is the check.

Scope

This clears one of the two deterministic failures. sun/security/ssl/X509KeyManager/PreferredKey.java on OpenJDK.Tests partition 7 is separate and still open, so neither #727 nor #730 goes fully green on this alone.

wasabii added 2 commits August 5, 2026 08:30
IKVM.Tools.Importer.Tests fails every row on net472 with

  Could not load file or assembly 'System.Collections.Immutable,
  Version=10.0.0.0' ---> ... 'Version=8.0.0.0'
  at IKVM.Tools.Importer.ImportOptions..ctor()

The cause is in the SDK's .NET Framework test host rather than in anything we
ship. testhost.net472.exe.config in 10.0.302 carries

  <bindingRedirect oldVersion="1.0.0.0-10.0.0.0" newVersion="10.0.0.0" />

for System.Collections.Immutable, and the host directory holds 10.0.0.0. So
IKVM.CoreLib's 8.0.0.0 reference is redirected up to 10.0.0.0, the loader
then finds the 8.0.0.0 copy sitting next to the tests, and the bind fails on
major version.

Bumping the two tool test projects puts 10.0.0.0 beside the tests, which is
what the host's redirect points at.

Deliberately not touching the pins in IKVM.deps.targets, IKVM.CoreLib,
ikvmc, ikvmstub or the SDK targets. ikvmc ships as a standalone executable
with its own config and never sees the test host's redirect, so this is a
test environment problem and not a product one. The pins in
IKVM.NET.Sdk.targets and IKVM.MSBuild/buildTransitive reach consumers, and
changing those to satisfy a test host quirk would take on real risk for no
gain.

The tests now run against a different System.Collections.Immutable than
production ships, which is a small loss of fidelity, but the alternative
changes what users get.

Not verified locally: the net472 build stops earlier on NETSDK1094 from
ikvmstub wanting a runtime identifier for ReadyToRun, which is unrelated and
already present. Restore is clean and net472 resolves to 10.0.10.
@wasabii
wasabii marked this pull request as draft August 5, 2026 17:02
@wasabii

wasabii commented Aug 5, 2026

Copy link
Copy Markdown
Contributor Author

Reverted — the change does not work, and makes things worse. Leaving the PR open as a draft because the diagnosis in the description is still correct and worth keeping; only the fix was wrong.

What CI showed

Job Before After
Tools.Importer.Tests:net472:win-x64 fail fail, identical error
Tools.Importer.Tests:net8.0:linux-x64 pass fail — importer exits 2

So it did not fix the target and it regressed Linux.

Why bumping the test project could never have worked

IKVM.refs.targets pulls IKVM.CoreLib in as:

<ProjectReference Include="...\IKVM.CoreLib\IKVM.CoreLib.csproj">
    <PrivateAssets>all</PrivateAssets>
    <OutputItemType>IkvmLibsItem</OutputItemType>
</ProjectReference>

IkvmLibsItem copies CoreLib's build output into the test directory, and that output carries the System.Collections.Immutable 8.0.0 that CoreLib itself resolved. The test project's own PackageReference never gets a say in which copy lands next to the tests. That is why the net472 error came back byte for byte.

What this means for the real fix

The assembly beside the tests is determined by IKVM.CoreLib, so satisfying the host's redirect means bumping IKVM.CoreLib — which is a product dependency change, exactly what the description argued against taking on for a test-host quirk.

That makes this a genuine trade-off rather than an oversight, and worth a decision rather than another guess:

  • bump System.Collections.Immutable in IKVM.CoreLib (and likely IKVM.deps.targets, IKVM.NET.Sdk.targets, IKVM.MSBuild/buildTransitive) so shipped and tested agree, accepting the consumer risk; or
  • stop the SDK test host applying its redirect to this assembly, if that is possible via runsettings or an explicit app.config that survives the temp-config merge; or
  • leave Tools.Importer.Tests:net472 excluded on Windows and record why.

The diagnosis of the mechanism stands: testhost.net472.exe.config redirects 1.0.0.0-10.0.0.0 to 10.0.0.0 and ships 10.0.0.0, while the app-local copy is 8.0.0.0.

Second attempt at the net472 bind failure, taking the other route: leave the
package versions alone and change the redirect instead.

The .NET Framework test host carries its own redirect in
testhost.net472.exe.config,

  <bindingRedirect oldVersion="1.0.0.0-10.0.0.0" newVersion="10.0.0.0" />

next to a 10.0.0.0 copy of the assembly. IKVM.CoreLib is built against
8.0.0.0, and the copy beside the tests comes from CoreLib's own output via
IkvmLibsItem in IKVM.refs.targets, so it is 8.0.0.0 too. The host redirects
the reference up to 10.0.0.0 and the bind fails on major version.

AutoGenerateBindingRedirects only emits 0.0.0.0-8.0.0.0 for this assembly,
because 8.0.0.0 is the highest anything resolves to, and that range does not
cover what the host asks for. An explicit app.config widening it to 10.0.0.0
while keeping the target at 8.0.0.0 points the bind back at the assembly that
is actually on disk.

Whether this survives is the open question: VSTest merges the test source's
config with the host's into a temp file, and it is not documented which side
wins for a duplicate identity. The first attempt, bumping the test project's
package reference, failed because the assembly beside the tests never came
from that reference in the first place. CI is the check.
@wasabii

wasabii commented Aug 5, 2026

Copy link
Copy Markdown
Contributor Author

Second attempt pushed, taking the other route: leave package versions alone and change the redirect instead.

What changed

An explicit app.config in IKVM.Tools.Importer.Tests:

<assemblyIdentity name="System.Collections.Immutable" publicKeyToken="b03f5f7f11d50a3a" culture="neutral" />
<bindingRedirect oldVersion="0.0.0.0-10.0.0.0" newVersion="8.0.0.0" />

Why this shape

AutoGenerateBindingRedirects emits 0.0.0.0-8.0.0.0 for this assembly, because 8.0.0.0 is the highest version anything in the graph resolves to. That range does not cover the 1.0.0.0-10.0.0.0 the host asks for, so the host's redirect is the one that applies and the reference goes up to 10.0.0.0 — where nothing is.

Widening the range to 10.0.0.0 while keeping the target at 8.0.0.0 points the bind back at the assembly that is genuinely on disk. No package version moves, so nothing consumers receive is affected.

What is genuinely uncertain

VSTest merges the test source's config with the host's into a temp file (the Fusion log shows C:\w\temp\tmp8A37.tmp), and it is not documented which side wins when both declare a redirect for the same identity. If the host's entry takes precedence regardless, this will fail the same way and the remaining options are the product-dependency bump or excluding the job.

Note also that IKVM.Tools.Importer.Tests.runsettings sets DisableAppDomain=True, so there is no separate app domain — the merge happens for the host process itself, which is why the app config is in play at all.

The first attempt failed because the assembly beside the tests never came from the test project's package reference. It arrives from IKVM.CoreLib's build output via IkvmLibsItem in IKVM.refs.targets, which is why bumping the reference changed nothing on Windows and only managed to regress Linux.

@wasabii
wasabii marked this pull request as ready for review August 6, 2026 03:52
@wasabii

wasabii commented Aug 6, 2026

Copy link
Copy Markdown
Contributor Author

This works. Marking ready.

Result

Job Before Now
Tools.Importer.Tests:net472:win-x64 fail pass (5m11s)
Tools.Importer.Tests:net8.0:linux-x64 fail on attempt 1 pass (2m53s)
Tools.Importer.Tests:net8.0:win-x64 pass pass

The target job is fixed, and unlike the first attempt there is no regression on Linux.

Why widening the range was the right lever

The host's redirect covers 1.0.0.0-10.0.0.0; AutoGenerateBindingRedirects only emitted 0.0.0.0-8.0.0.0, because 8.0.0.0 is the highest version anything in the graph resolves to. The narrower range simply did not apply to the reference, so the host's won and sent the bind to a version that is not present.

Declaring 0.0.0.0-10.0.0.0 -> 8.0.0.0 explicitly makes the test assembly's entry cover the same range, and it is the one that takes effect. No package version moves, so nothing consumers receive changes.

Remaining failures are not from this PR

Failure Cause Fixed by
partition 0 net8.0 win + linux java/awt/Choice/ResizeAutoClosesChoice — a known flake #730
partition 7 net8.0 win + linux PreferredKey, expired test certificate #733

Neither can be caused by this change, which adds a single app.config to the importer test project and touches nothing else.

Note for reviewers

The first attempt on this branch bumped the test project's System.Collections.Immutable package reference and was reverted. It could not have worked: the copy of the assembly beside the tests comes from IKVM.CoreLib's build output via IkvmLibsItem in IKVM.refs.targets, not from the test project's own reference. The revert is in the history.

@wasabii
wasabii merged commit 6300097 into main Aug 7, 2026
176 of 195 checks passed
@wasabii
wasabii deleted the fix/importer-net472-immutable branch August 7, 2026 17:53
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.

1 participant