Skip to content

Test asset NuGet restore: fragile resolution of Microsoft.Testing.Platform via transitive CodeCoverage prerelease (NU1102) #9030

@Evangelink

Description

@Evangelink

Summary

Test assets using <PackageReference Include="MSTest" Version="$MSTestVersion$" /> (≈20 csprojs in test/IntegrationTests/) can fail to restore with NU1102 when the local-build chain demands a Microsoft.Testing.Platform prerelease that isn't in any of the test-asset's configured feeds.

Concrete repro: see the MSTestJUnitReportMTPRetry asset in test/IntegrationTests/MSTest.Acceptance.IntegrationTests/JUnitReportTests.cs — failed during PR #9029 CI runs and several previous builds.

Failure chain

  1. Test-asset csproj: <PackageReference Include="MSTest" Version="$MSTestVersion$" /> → resolves to local-built MSTest 4.3.0-ci.
  2. MSTest 4.3.0-ci's packed nuspec hardcodes:
    <dependency id="Microsoft.Testing.Extensions.CodeCoverage" version="18.9.0-preview.26309.4" />
    (Pinned via eng/Versions.propsMicrosoftTestingExtensionsCodeCoverageVersion.)
  3. Microsoft.Testing.Extensions.CodeCoverage 18.9.0-preview.26309.4 lives only on the dotnet-tools feed. Its nuspec transitively demands:
    <dependency id="Microsoft.Testing.Platform" version="2.3.0-preview.26308.7" />
  4. Test-asset's NuGet.config (TestAsset.GetNuGetConfig) lists 6 feeds — none includes dotnet-tools. The closest matches:
    • local-shipping has MTP 2.3.0-ci — sorts below 2.3.0-preview.26308.7 in SemVer 2.0 (c < p).
    • dotnet-public maxes out at MTP 2.2.3.
  5. NuGet emits NU1102 for MTP. The error misleadingly points at the local feed instead of the actual upstream constraint.

Root cause

Two-part design weakness in the test-asset infrastructure:

  1. No exact-match pinning: Version="$X$" is interpreted by NuGet as [$X$, ) — open-ended minimum. Drift to higher prereleases from any configured feed is technically allowed.
  2. No local-folder priority: packageSourceMapping in the generated NuGet.config uses <package pattern="*"/> for every feed — no priority for local. There is no isolation of testfx-family packages.

Combined with MSTest's packed nuspec hardcoding a CodeCoverage prerelease that only exists on dotnet-tools, this creates a fragile resolution chain that explodes for any test asset using the MSTest meta package.

Proposed fixes (mix and match)

A. Add dotnet-tools to TestAsset's default NuGet.config

Smallest mechanical change; mirrors the repo's top-level NuGet.config. Restores parity with the main build's restore chain.

 <add key="local-tmp-packages" value="..." />
 <add key="dotnet-public" value="..." />
+<add key="dotnet-tools" value="https://pkgs.dev.azure.com/dnceng/public/_packaging/dotnet-tools/nuget/v3/index.json" />
 <add key="dotnet10" value="..." />
 <add key="dotnet11" value="..." />

B. Exact-match pinning in test-asset csprojs

Use Version="[$X$]" everywhere. Hardens against version drift on direct PackageReferences.

- <PackageReference Include="MSTest" Version="$MSTestVersion$" />
+ <PackageReference Include="MSTest" Version="[$MSTestVersion$]" />

C. Per-package packageSourceMapping

Force testfx-family packages to come only from local feeds (and dotnet-tools for CodeCoverage previews):

<packageSource key="local-shipping">
    <package pattern="Microsoft.Testing.*" />
    <package pattern="MSTest*" />
</packageSource>
<packageSource key="dotnet-tools">
    <package pattern="Microsoft.Testing.Extensions.CodeCoverage" />
</packageSource>
<packageSource key="dotnet-public">
    <package pattern="*" />
</packageSource>

D. Downgrade CodeCoverage dep in MSTest's packed nuspec to nearest stable

Cleanest at the source — pin to 18.8.0 (stable, on dotnet-public) for the packed metadata while still consuming the preview at build time. Requires coordinating with the VSTest CodeCoverage release train and verifying no behavioral regression.

Recommended path

I'd suggest A + B + C combined:

  • A restores feed parity (smallest change, instant relief).
  • B prevents direct-ref drift (general hardening).
  • C makes future failures fail-fast with a clearer error message.

D is the right long-term solution but is a larger conversation about how MSTest's nuspec dependencies should be versioned (always-stable vs. always-preview-matched).

Related

Metadata

Metadata

Assignees

No one assigned

    Labels

    No labels
    No labels

    Type

    No fields configured for Bug.

    Projects

    No projects

    Milestone

    No milestone

    Relationships

    None yet

    Development

    No branches or pull requests

    Issue actions