Add Native AOT Components testing harness - #68289
Merged
Merged
Conversation
Contributor
There was a problem hiding this comment.
Pull request overview
Adds a Native AOT E2E testing harness to Microsoft.AspNetCore.Components.Testing, including a build-only Microsoft.AspNetCore.Components.Testing.NativeAot package (source generator + transitive targets), manifest support to distinguish “startupHook” vs “compiled” harness modes, and package-consumer integration coverage for both inert normal builds and Native AOT publish/launch.
Changes:
- Introduces a build-only Native AOT harness generator/package and wires it into test assets and packing flow.
- Extends E2E manifest generation + runtime loading/validation to support per-app
E2EAppMode, Native AOT RIDs, and aharnessModefield. - Updates server launch environment construction to omit managed startup-hook injection for compiled harnesses, with new unit/integration tests.
Reviewed changes
Copilot reviewed 21 out of 21 changed files in this pull request and generated 2 comments.
Show a summary per file
| File | Description |
|---|---|
| src/Components/Testing/testassets/PackageConsumer/Tests/PackageConsumer.Tests.csproj | Adds per-app E2E metadata (mode/nativeaot/RID) and forwards build properties for the package-consumer test scenario. |
| src/Components/Testing/testassets/PackageConsumer/App/PackageConsumer.App.csproj | Enables compiled-harness publish settings (AOT, RIDs) when E2ECompileTestHarness is set; references the new Native AOT build-only package. |
| src/Components/Testing/testassets/Directory.Build.props | Adds a repo/test-asset switch to disable E2E app preparation in excluded/source-only builds. |
| src/Components/Testing/test/ServerInstanceTests.cs | Adds coverage for compiled-harness env var behavior and failure modes. |
| src/Components/Testing/test/PackageIntegrationTests.cs | Adds package asset validation for the Native AOT package plus package-consumer coverage for inert/Native AOT publish + launch. |
| src/Components/Testing/test/Microsoft.AspNetCore.Components.Testing.Tests.csproj | Packs the new Native AOT package for integration tests and adds Native AOT publish orchestration for the package consumer. |
| src/Components/Testing/test/Generators/NativeAotTestHarnessGeneratorTests.cs | New unit tests validating generator gating and emitted source characteristics. |
| src/Components/Testing/test/GenerateE2EManifestTaskTests.cs | Expands manifest task tests for per-app mode overrides and Native AOT validation/selection. |
| src/Components/Testing/test/E2EManifestTests.cs | Adds manifest deserialize/validate coverage for the new harnessMode field. |
| src/Components/Testing/tasks/GenerateE2EManifest.cs | Implements per-app mode resolution, Native AOT validation, exe selection by RID, and emits harnessMode. |
| src/Components/Testing/tasks/E2EManifestModel.cs | Adds harnessMode to the serialized manifest model. |
| src/Components/Testing/src/Infrastructure/ServerInstance.cs | Refactors env-var construction/application to support compiled harnesses (no managed injection variables). |
| src/Components/Testing/src/Infrastructure/E2EManifest.cs | Adds manifest validation on load, including harness-mode validation. |
| src/Components/Testing/src/Infrastructure/E2EAppEntry.cs | Adds harness-mode constants + JSON property for harnessMode. |
| src/Components/Testing/nativeaot/NativeAotTestHarnessGenerator.cs | New incremental generator that emits a compiled-harness hosting startup + readiness/parent-process monitoring. |
| src/Components/Testing/nativeaot/Microsoft.AspNetCore.Components.Testing.NativeAot.csproj | New build-only packable project for the Native AOT harness generator + transitive build assets. |
| src/Components/Testing/nativeaot/buildTransitive/Microsoft.AspNetCore.Components.Testing.NativeAot.targets | Adds analyzer inclusion gated by E2ECompileTestHarness. |
| src/Components/Testing/nativeaot/buildTransitive/Microsoft.AspNetCore.Components.Testing.NativeAot.props | Makes E2ECompileTestHarness visible to the generator via CompilerVisibleProperty. |
| src/Components/Testing/eng/targets/Microsoft.AspNetCore.Components.Testing.targets | Updates E2E app preparation to support per-app modes, Native AOT publish wiring, and mode validation. |
| src/Components/Testing/eng/targets/Microsoft.AspNetCore.Components.Testing.props | Adds EnableE2EAppPreparation defaulting for decoupled disabling of app prep. |
| AspNetCore.slnx | Adds the new Native AOT project to the solution. |
💡 Add a code-review agent skill for context-aware, tailored reviews. Learn more in the docs.
Comment on lines
+69
to
+79
| var includeBuild = mode.Equals("build", StringComparison.OrdinalIgnoreCase) | ||
| || mode.Equals("all", StringComparison.OrdinalIgnoreCase); | ||
| var includePublish = mode.Equals("publish", StringComparison.OrdinalIgnoreCase) | ||
| || mode.Equals("all", StringComparison.OrdinalIgnoreCase); | ||
| var isBothMode = mode.Equals("all", StringComparison.OrdinalIgnoreCase); | ||
| var name = item.GetMetadata("Filename"); | ||
| var projectPath = item.GetMetadata("FullPath"); | ||
| var publicUrl = item.GetMetadata("E2EPublicUrl") ?? ""; | ||
| var isCompiledHarness = item.GetMetadata("E2ENativeAot").Equals("true", StringComparison.OrdinalIgnoreCase); | ||
| var runtimeIdentifier = item.GetMetadata("E2ERuntimeIdentifier"); | ||
|
|
Comment on lines
+179
to
+184
| if (completed != readinessTask) | ||
| { | ||
| var output = await process.StandardOutput.ReadToEndAsync(TestContext.Current.CancellationToken); | ||
| var error = await process.StandardError.ReadToEndAsync(TestContext.Current.CancellationToken); | ||
| Assert.Fail($"Native app exited or timed out before readiness. stdout: {output}\nstderr: {error}"); | ||
| } |
javiercn
force-pushed
the
javiercn-components-testing-native-aot
branch
4 times, most recently
from
August 8, 2026 18:34
5c3a7e9 to
0bf07bc
Compare
3 tasks
javiercn
force-pushed
the
javiercn-components-testing-native-aot
branch
3 times, most recently
from
August 9, 2026 08:45
6fe3906 to
39bf2d2
Compare
maraf
approved these changes
Aug 10, 2026
Add a build-only Native AOT package, compiled application harness, manifest/runtime support, and package-consumer validation for native app publishing and launch. Co-authored-by: Copilot App <223556219+Copilot@users.noreply.github.com> Copilot-Session: a5425cd4-aa5e-4199-846c-fbf11893985b
Run the publish in a fresh dotnet process after restore so newly generated Native AOT imports and ASP.NET runtime-pack inputs are available on clean consumers. Co-authored-by: Copilot App <223556219+Copilot@users.noreply.github.com>
Carry standard ProjectReference configuration and additional properties into the fresh publish evaluation while keeping the required harness, AOT, and RID properties authoritative. Co-authored-by: Copilot App <223556219+Copilot@users.noreply.github.com>
Let each E2E project own its AOT, RID list, self-contained, and restore configuration. Add per-reference E2EAppMode overrides while keeping repository-specific gating and fixture restore outside the shipped targets. Co-authored-by: Copilot App <223556219+Copilot@users.noreply.github.com>
Keep the isolated package consumer publish evaluation aligned with its RID-specific restore without adding repository behavior to shipped targets. Co-authored-by: Copilot App <223556219+Copilot@users.noreply.github.com>
Keep server identity, app metadata, direct URL, and public URL available to external E2E tests. Co-authored-by: Copilot App <223556219+Copilot@users.noreply.github.com>
Suppress the source-tree Components.Testing target import when the outer build sets SkipTestBuild, preventing excluded E2E tests from traversing package assets without restore. Co-authored-by: Copilot App <223556219+Copilot@users.noreply.github.com>
javiercn
force-pushed
the
javiercn-components-testing-native-aot
branch
from
August 10, 2026 08:47
f7cf4e0 to
5c893a6
Compare
maraf
approved these changes
Aug 10, 2026
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment
Add this suggestion to a batch that can be applied as a single commit.This suggestion is invalid because no changes were made to the code.Suggestions cannot be applied while the pull request is closed.Suggestions cannot be applied while viewing a subset of changes.Only one suggestion per line can be applied in a batch.Add this suggestion to a batch that can be applied as a single commit.Applying suggestions on deleted lines is not supported.You must change the existing code in this line in order to create a valid suggestion.Outdated suggestions cannot be applied.This suggestion has been applied or marked resolved.Suggestions cannot be applied from pending reviews.Suggestions cannot be applied on multi-line comments.Suggestions cannot be applied while the pull request is queued to merge.Suggestion cannot be applied right now. Please check back later.
Summary
This document proposes adding Native AOT application testing to
Microsoft.AspNetCore.Components.Testingthrough a build-only companion package. The feature lets an E2E test project publish an application with a compiled readiness and parent-process monitoring harness, describe it in a portable manifest, and launch it as a native executable without adding the testing library, MSTest, Playwright, YARP, startup hooks, or reflection-based test infrastructure to the application at runtime.This PR is stacked on #67083 and extends its package-based application discovery, publishing, manifest, and launch model. The application remains responsible for its Native AOT configuration and matching restore; the test project selects which application reference is published, its mode, and the runtime identifier for the current invocation.
Goals
Enable external consumers to test Native AOT ASP.NET Core applications through the same Components.Testing manifest and server lifecycle used for managed applications.
Keep the companion package inert during ordinary builds and prevent it from contributing runtime
liborrefassemblies to the application.Produce a portable published payload whose manifest identifies a compiled harness and whose native executable can signal readiness, terminate when its test parent exits, and serve requests without startup-hook dependencies.
Allow each application reference to select its own E2E preparation mode and runtime identifier while leaving Native AOT configuration, supported RIDs, self-contained behavior, and restore ownership in the application project.
Fail early and explicitly when the requested scenario cannot produce or safely launch a compiled Native AOT application.
Non-goals
This proposal does not make an application Native AOT compatible. The application must already satisfy Native AOT trimming, dependency, and platform requirements.
This proposal does not choose or restore runtime identifiers on behalf of the application. The application declares its supported RIDs and is restored for the RID selected by the test invocation.
This proposal does not cross-compile Native AOT applications or publish multiple RIDs in one test invocation.
This proposal does not replace the existing startup-hook harness for managed build or publish scenarios.
This proposal does not add repository-specific CI, Helix, source-build, or source-tree orchestration to the shipped package assets.
Proposed solution
Ship
Microsoft.AspNetCore.Components.Testing.NativeAotas a build-only companion package containing the compiled-harness generator and transitive build assets. The package can be referenced unconditionally withPrivateAssets="all"; it activates only when Components.Testing publishes an application reference withE2ECompileTestHarness=true.The application project owns
PublishAot,RuntimeIdentifiers, self-contained configuration, and the matching restore. The test project marks the application as an E2E app, choosespublishmode for that reference, identifies it as Native AOT, and selects one RID. Components.Testing publishes the application with the compiled harness enabled, emits a manifest entry withharnessMode: "compiled", and launches the resulting native executable without startup-hook environment variables.Reference the companion package without affecting normal builds
The application references the companion package privately and declares its Native AOT configuration:
A normal Build remains managed and does not generate the compiled harness or copy a Components.Testing Native AOT assembly into the application output.
Publish one application as Native AOT
The test project selects publish mode and one RID on the application reference:
The selected application is published for
win-x64with its compiled test harness. Other E2E application references may continue using the global default mode or specify their ownE2EAppMode.Restore and publish for a selected RID
Before the test project publishes the payload, the application is restored using the same Native AOT properties and selected RID that Publish will use:
The consumer may restore all declared RIDs or restore only the RID selected by the test invocation. Components.Testing does not repair or replace an incompatible restore graph.
Start and use the compiled application in a test
Tests use the same server lifecycle as other Components.Testing applications:
The generated application harness reports readiness to the test host and watches the parent process automatically.
ServerInstanceexposes itsId,AppName, directAppUrl, manifestPublicUrl, and proxiedTestUrlfor test scenarios that need routing, diagnostics, or externally registered callback URLs.Produce a portable compiled manifest entry
The published manifest records the native executable, its relative working directory, and
harnessMode: "compiled". The payload can be copied to another provisioned machine and launched without the source checkout, a managed application DLL fallback,DOTNET_STARTUP_HOOKS, orASPNETCORE_HOSTINGSTARTUPASSEMBLIES.Mix managed and compiled applications
A test project may combine build-mode managed applications, publish-mode managed applications, and publish-mode Native AOT applications.
E2EAppModeon each ProjectReference overrides the global default, so only references explicitly configured for Native AOT publish require anE2ERuntimeIdentifierand compiled executable.Extend application-owned Native AOT configuration
Applications may use normal SDK properties, publish profiles, conditional property groups, and
RuntimeIdentifiersto control supported platforms and AOT behavior. Components.Testing forwards standard ProjectReference configuration, platform, target-framework, and additional properties while keeping the required compiled-harness flag and selected RID authoritative for the test publish.Reject Native AOT outside publish mode
If
E2ENativeAot=trueis used withE2EAppMode=buildorall, payload preparation fails with an error explaining that compiled Native AOT applications requirepublishmode.Reject a missing runtime identifier
If a Native AOT ProjectReference does not provide
E2ERuntimeIdentifier, payload preparation fails before publishing because one concrete RID is required for the invocation.Reject missing or managed publish output
If publishing does not produce the expected native executable, manifest generation fails. A compiled entry never falls back to
dotnet App.dll, because that would misrepresent the payload as Native AOT.Reject managed service overrides for compiled applications
If a test tries to configure a compiled application through the managed
ConfigureServicesoverride mechanism, server startup fails with an explicit error. Compiled applications cannot load arbitrary managed test methods through the startup-hook mechanism; application customization must be expressed in AOT-compatible application configuration.Surface SDK restore and publish failures
If the application was not restored for the selected RID, does not include the required Native AOT packs, or is not AOT compatible, the standard SDK restore or publish error is surfaced. Components.Testing does not silently restore with different settings or produce a success-shaped managed fallback.
Assumptions
The application targets a .NET SDK and ASP.NET Core version that support Native AOT for the selected RID.
The companion package version is compatible with the main
Microsoft.AspNetCore.Components.Testingpackage version.The application declares every RID that consumers may select and completes a matching restore before a no-restore publish path is used.
The machine performing Native AOT publish has the required native toolchain and supports the selected RID; cross-compilation is not assumed.
One test invocation selects exactly one RID for each Native AOT application reference.
The published payload is transferred only to a compatible operating system and architecture.
References
f7cf4e041eafb3151bcfb20f76e726bf1e17cc74