Skip to content

Fix PackageDeploymentManager test cascade: force-close blocking app on ERROR_PACKAGES_IN_USE retry - #6693

Draft
Vineeth Thomas Alex (vineeththomasalex) wants to merge 2 commits into
release/dev/monobuildfrom
user/vithoma/fix-packagedeploymentmanager-test-isolation
Draft

Fix PackageDeploymentManager test cascade: force-close blocking app on ERROR_PACKAGES_IN_USE retry#6693
Vineeth Thomas Alex (vineeththomasalex) wants to merge 2 commits into
release/dev/monobuildfrom
user/vithoma/fix-packagedeploymentmanager-test-isolation

Conversation

@vineeththomasalex

@vineeththomasalex Vineeth Thomas Alex (vineeththomasalex) commented Aug 17, 2026

Copy link
Copy Markdown
Collaborator

Problem

221 of the ~228 failures on WinAppSDK-Test-Foundation (def 192441) stem from one test-isolation defect:

  • PackageDeploymentManagerTests_Register (190 failures — whole class cascades from ClassSetup/fixture failure with empty error text)
  • PackageDeploymentManagerTests_IsPackageRegistrationPending (21 of 28 failures)
  • PackageDeploymentManagerTests_IsReadyOrNewerAvailable (10 failures)

Reference runs:

Root cause

Test::Packages::AddPackage() already retries AddPackageAsync up to 5 times with exponential backoff (~15s total) when it hits ERROR_PACKAGES_IN_USE (x80073D02), but always reissues with DeploymentOptions::None.

RemovePackage_Blacker() / RemovePackage_Black() call into this exact AddPackage() path whenever the target package is staged-but-not-registered (they register it first so it can be removed). These helpers are called pervasively across PackageDeploymentManagerTests_Register, _IsPackageRegistrationPending, and _IsReadyOrNewerAvailable — including from TEST_CLASS_SETUP/TEST_CLASS_CLEANUP.

PackageDeploymentManagerTests_IsPackageRegistrationPending's *_Pending tests activate Test.PackageManager.M.Black (same package family as Blacker) and defer-register Blacker while it's running. A prior fix (#6678) added a wait for the activated process to exit, but the OS-side "in use" bookkeeping for the package family doesn't necessarily clear the instant the process handle signals — the deferred registration completing is a separate async step. When it hasn't settled by the time the next RemovePackage_Blacker() call fires (in the same class's cleanup, or the next class's setup), AddPackageAsync fails with x80073D02 again, and 5 retries at ~15s total isn't always enough. A single stuck call inside a TEST_CLASS_SETUP/TEST_CLASS_CLEANUP fixture fails the whole fixture, and TAEF cascades every test in the class to [Failed] with empty error text — and the leftover staged package repeats the same race in the next class that runs, which is why the cascade spans three classes.

Confirmed directly from the ADO test results for build 154915868 (IsPackageRegistrationPendingForUser_NotInstalled, _Registered, _Pending, and both IsReadyOrNewerAvailable failures all show the identical AddPackageAsync('...Blacker...') = 0x80073D02 ... Test.PackageManager.M.Black_1.2.3.4... failure at WindowsAppRuntime.Test.Package.h:459; all 38 Register::* tests fail with empty error text from the cascaded ClassSetup).

Fix

Once AddPackageAsync fails with ERROR_PACKAGES_IN_USE, escalate to DeploymentOptions::ForceTargetApplicationShutdown on the next retry so the deployment service force-closes the blocking process itself instead of guessing how long to wait — this is the option the platform documents for exactly this error ("If this package is currently in use, the processes associated with the package are shut down forcibly so that registration can continue."). The first attempt is left as DeploymentOptions::None so a clean install is never destructive; only a confirmed ERROR_PACKAGES_IN_USE failure escalates subsequent retries.

This is a single, universal choke point: every RemovePackage_Blacker()/RemovePackage_Black() call across all three affected test classes funnels through this same AddPackage() function, so the fix addresses the cascade regardless of which specific test left the package family "in use".

Scope

  • Test-infrastructure only ( est/inc/WindowsAppRuntime.Test.Package.h). No product code changed.
  • Does not touch the separate, already-known IsPackageRegistrationPending_Pending / IsPackageRegistrationPendingForUser_Pending API-behavior assertion at IsPackageRegistrationPending.cpp:108 (API returns alse for the pending state) — that's out of scope per a real product-behavior investigation, tracked separately.
  • ABForward::FunctionalTests::ClassInit (2 failures) is a separate fixture, not addressed here.

Verification plan

Will validate via a targeted rebuild-stage run of WinAppSDK-Test-Foundation (def 192441) and diff the failure list against build 154915868

…n ERROR_PACKAGES_IN_USE retry

Test::Packages::AddPackage() retries AddPackageAsync up to 5 times with
exponential backoff (~15s total) when it hits ERROR_PACKAGES_IN_USE
(0x80073D02), but always reissues with DeploymentOptions::None. When an
earlier test's activated app (e.g. IsPackageRegistrationPending_Pending's
Test.PackageManager.M.Black instance) hasn't fully released its package
lock within that window -- or a deferred registration from a prior test
hasn't completed settling -- every retry fails identically and the
in-place upgrade to Test.PackageManager.M.Blacker never makes progress.

RemovePackage_Blacker()/RemovePackage_Black() call into this same
AddPackage() path whenever the target package is staged-but-not-registered
(to register it before removal), and are invoked pervasively across
PackageDeploymentManagerTests_Register, _IsPackageRegistrationPending, and
_IsReadyOrNewerAvailable -- including from TEST_CLASS_SETUP/TEST_CLASS_CLEANUP.
A single stuck AddPackage() there fails the fixture and TAEF cascades every
test in the class to [Failed] with empty error text, then the leftover
staged package repeats the same race in the next class that runs.

Fix: once AddPackageAsync fails with ERROR_PACKAGES_IN_USE, escalate to
DeploymentOptions::ForceTargetApplicationShutdown on the next retry so the
deployment service force-closes the blocking process itself instead of us
guessing how long to wait -- this is the option the platform documents for
exactly this error. The first attempt is left as DeploymentOptions::None
so a clean install is never destructive.

This should eliminate the 0x80073D02 cascade behind ~221 failures in
Test-Foundation (PackageDeploymentManagerTests_Register,
_IsPackageRegistrationPending, _IsReadyOrNewerAvailable). It does not
change the unrelated, already-known IsPackageRegistrationPending_Pending
API-behavior assertion at IsPackageRegistrationPending.cpp:108.

Co-authored-by: Copilot <223556219+Copilot@users.noreply.github.com>
Copilot-Session: 7a243429-2b18-4b9a-aea2-f207cc2ea908
@azure-pipelines

Copy link
Copy Markdown
Azure Pipelines:
There may be pipelines that require an authorized user to comment /azp run to run.

@vineeththomasalex

Copy link
Copy Markdown
Collaborator Author

Verified: fix confirmed via targeted rebuild-stage validation

Validated via a minimal, targeted run — no full monobuild triggered. Used the monobuild's built-in single-stage rebuild mechanism (useBuildOutput_RebuildStage=Foundation, useBuildOutput_BuildId=154889062) on WinAppSDK-MonoBuild-Nightly (def 190463), overriding only the WindowsAppSDKFoundation repo resource to this branch (refs/heads/user/vithoma/fix-packagedeploymentmanager-test-isolation) so every other component (Base, Widgets, WinUI, WinML, InteractiveExperiences, DWriteCore, etc.) reused artifacts from build 154889062 unchanged. Confirmed via the pipeline timeline that only the Foundation stage + its downstream Foundation Test Trigger ran; every other stage reported skipped.

Result: 228 → 14 failures (-214), zero cascade signal remaining

Baseline (build 154915868, pre-fix) This fix (build 155084977)
0x80073D02 / ERROR_PACKAGES_IN_USE occurrences present, 38+ times 0
Setup fixture '...ClassSetup' failed occurrences present 0
PackageDeploymentManagerTests_Register failures 190 0
PackageDeploymentManagerTests_IsReadyOrNewerAvailable failures 10 0
PackageDeploymentManagerTests_IsPackageRegistrationPending cascade failures 21 of 28 0
Total failures (all 12 test configs) 228 14

The remaining 14 failures are exactly the two known, out-of-scope, real product-behavior tests called out in scope (IsPackageRegistrationPending_Pending and its ForUser sibling, both failing at IsTrue(...IsPackageRegistrationPending...) — the documented IsPackageRegistrationPending.cpp:108-class assertion where the API returns false for the pending state) — one occurrence of each, in exactly the 7 configs that previously showed any package-related failures. Confirmed by pulling every Failed result's errorMessage across all 12 test-run configurations directly from the ADO Test Results API: there is not a single remaining 0x80073D02/ClassSetup/empty-error-text cascade result anywhere in the matrix.

ABForward::FunctionalTests::ClassInit (2 failures, called out as separate/out of scope) did not appear as a failure in this run.

Add a short note to the AddPackage() comment clarifying that the
escalation can only ever close a process left over from an earlier,
already-finished test - no test installs the package it's actively
exercising via this helper while that app is running (confirmed: the
IsPackageRegistrationPending "_Pending" tests exercise the in-use/deferred
scenario through AddPackageByUri's DeferRegistrationWhenPackagesAreInUse
path, which this change doesn't touch) - and that unconditional use of
ForceApplicationShutdown in Shared.cpp's and TestSetupAndTeardownHelper.h's
InstallPackage() helpers is existing precedent for this exact mitigation
in this test suite.

Co-authored-by: Copilot <223556219+Copilot@users.noreply.github.com>
Copilot-Session: 7a243429-2b18-4b9a-aea2-f207cc2ea908
@vineeththomasalex

Copy link
Copy Markdown
Collaborator Author

/azp run

@azure-pipelines

Copy link
Copy Markdown
Azure Pipelines:
Successfully started running 1 pipeline(s).
1 pipeline(s) were filtered out due to trigger conditions.

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Projects

None yet

Development

Successfully merging this pull request may close these issues.

2 participants