Workaround WindowsAppSDK#6394: copy project .pri into AOT publish output#360
Conversation
|
CI failure is unrelated — the Unit Tests job hit a known-flaky threading test: The assertion is Evidence this is pre-existing flake, not my PR:
Reran the failed job. |
Root cause: WindowsAppSDK's NativeAOT publish pipeline does not copy the project .pri (generated by _GenerateProjectPriFile) into the publish output for unpackaged apps (WindowsPackageType=None). The MakePRI item-group is gated on AppxPackage=true, so unpackaged apps fall through. Same applies to .xbf files emitted by the XAML compiler. Upstream tracking: microsoft/WindowsAppSDK#6394 (OPEN against 1.8 and 2.0). Symptoms previously attributed to multiple unrelated Reactor framework bugs were all manifestations of this one missing file: - TabView ctor throws FileNotFoundException from ResourceAccessor::GetLocalizedStringResource. - NavigationView template-apply throws the same; Reactor's error boundary renders an error TextBlock instead of the requested content. - Application.Current.Resources loads empty (0 merged / 0 themed / 0 keys) because Application.LoadComponent cascades through MRT for type lookups. - Every ThemeRef.Resolve returns null; .Foreground(Theme.X) falls back to defaults. Fix: add a small post-Publish MSBuild target that copies $(OutputPath)$(AssemblyName).pri and any .xbf files into $(PublishDir). Scoped to Reactor.AppTests.Host.csproj since that is currently the only AOT-published exe in the repo; copy verbatim into any other Reactor app that uses PublishAot=true with WindowsPackageType=None. Remove once WindowsAppSDK#6394 ships. Skip-list impact (tests/Reactor.AppTests.Host/SelfTest/SelfTestRunner.cs): - 108 skips -> 40 skips (net 68 newly-passing AOT fixtures). - All 60 NATIVE_CRASH entries eliminated. - Remaining 40 are all ASSERT_FAIL in pre-acknowledged reflection-heavy subsystems: Devtools/MCP (27), PropertyGrid auto-discovery (9), ControlUpdate_Collections, CoreCov2_UseObservableTreeHook, and the two Issue142 third-party XAML metadata fixtures. Verification: - JIT selftest: 735/735 fixtures, 2614 ok, 0 not_ok, 0 bail (unchanged). - AOT selftest: 735 plan, 695 ran, 40 skipped, 0 not_ok, 0 bail. - Reactor.Tests unit suite: Passed 8381, Failed 0, Skipped 46 (Yoga generated, pre-existing). - Reactor.csproj builds 0 errors (no library reflection added; library remains AOT-clean). Documentation: docs/aot-support.md gets a new "Required publish-time workarounds" section explaining #6394, plus updates to the works / does-not-work tables reflecting that built-in WinUI controls and ThemeRef.Resolve now work under AOT with the workaround in place. Co-authored-by: Copilot <223556219+Copilot@users.noreply.github.com>
…obal TaskScheduler.UnobservedTaskException race The three Use*ThreadingTests classes (UseInfiniteResource, UseMutation, UseResource) each subscribe to the process-wide TaskScheduler.UnobservedTaskException event in their constructor and assert that no unobserved exceptions occurred at the end of every test. With xUnit's default parallel test scheduling, the three classes race each other: an unobserved exception raised by a Task originating in one test class can fire the event handler in any of the others, breaking the AssertNoUnobserved() invariant. Symptom in CI: random failures across the family, e.g. - UseResourceThreadingTests.Fetcher_Observed_Cancellation_Is_Silent_Not_Error (main 3c3bed9) - UseInfiniteResourceThreadingTests.Refresh_During_InFlight_Cancels_And_Restarts (PR #360) - UseMutationThreadingTests.Unmount_Cancels_Pending_OnError_Does_Not_Fire (PR #360 rerun) Fix: tag all three classes with [Collection("UnobservedTaskException")]. xUnit serializes classes that share a collection name, so they no longer run concurrently and the global event handlers no longer see each other's tasks. Same convention as the existing [Collection("ConsoleTests")] grouping for Console.Out/Error-mutating tests. Verified: 10x stress run of all 19 threading tests, 0 failures. Co-authored-by: Copilot <223556219+Copilot@users.noreply.github.com>
42160a8 to
1e342b8
Compare
|
Updated with a targeted fix for the failing unit test. Root causeThe failures were a pre-existing flake in the Use*ThreadingTests family, exposed (but not caused) by this PR. All three test classes —
— subscribe to the process-wide Evidence the failures are unrelated to this PR's AOT changes (three different tests in the family across three different runs, including a failure on main):
FixTag all three classes with Verified locally: 10x stress run of all 19 threading tests, 0 failures. |
Summary
Diagnoses and works around a single WindowsAppSDK NativeAOT publish bug that was masquerading as ~10 unrelated Reactor framework issues. Net result: 68 of 108 previously-skipped AOT selftest fixtures now pass, including all 60 NATIVE_CRASH entries. JIT baseline is unchanged at 735/735.
Root cause
microsoft/WindowsAppSDK#6394 (OPEN against 1.8 and 2.0): when publishing an unpackaged WinUI 3 app (
WindowsPackageType=None) withPublishAot=true, the WindowsAppSDK build pipeline generates$(AssemblyName).priinto$(TargetDir)but does not copy it into$(PublishDir). The PRI is wired into publish only behind<Condition>'$(AppxPackage)' == 'true'</Condition>, so unpackaged apps fall through. The same gap applies to.xbffiles.This one missing file produced what looked like several independent failures:
TabViewctor throwsFileNotFoundExceptionfromResourceAccessor::GetLocalizedStringResourceNavigationViewtemplate-apply throws the same exception (caught by Reactor's error boundary)Application.Current.Resourcesloads empty (0/0/0)Application.LoadComponentcascades through MRT for type lookupsThemeRef.Resolve(...)returnsnullfor every keyXamlControlsResourceswas empty, see aboveConfirmed by literally copying
Reactor.AppTests.Host.priinto the publish folder and re-running: every symptom resolved in one shot.Fix
Small post-
PublishMSBuild target intests/Reactor.AppTests.Host/Reactor.AppTests.Host.csprojthat copies the PRI (and any.xbffiles) into the publish output:Scoped to the test host since it's currently the only AOT-published exe in the repo. To be removed once WindowsAppSDK#6394 ships.
The Reactor library itself is untouched; it remains AOT-clean.
Skip-list cleanup (
SelfTestRunner.DefaultAotSkipPatterns)108 → 40 entries. Every NATIVE_CRASH skip is gone. The remaining 40 are ASSERT_FAIL in pre-acknowledged reflection-heavy subsystems:
docs/aot-support.mdas not-yet-AOT-clean.ControlUpdate_Collections,CoreCov2_UseObservableTreeHook(both pre-existing assertion bugs),Issue142_CustomControlPrivateDp_Renders,Issue142_ThirdPartyControlPrivateDp_Renders(need a hand-writtenIXamlMetadataProvidersince the XAML compiler only emits one when a project has a.xamlfile).Verification
Reactor.AppTests.Host --self-test)Reactor.Testsunit suiteReactor.csprojlibrary buildFiles changed
tests/Reactor.AppTests.Host/Reactor.AppTests.Host.csproj— adds_CopyWinUIResourcesForAotMSBuild target.tests/Reactor.AppTests.Host/SelfTest/SelfTestRunner.cs—DefaultAotSkipPatternsshrinks 108 → 40 with new comments grouping the remaining entries by root cause.docs/aot-support.md— new "Required publish-time workarounds" section explaining #6394; works/does-not-work tables updated to reflect that built-in WinUI controls andThemeRef.Resolvework under AOT with the workaround in place.