Fix iOS integration test simulator boot race condition#33884
Conversation
When launching iOS apps via XHarness/mlaunch, a race condition can occur where the simulator reports as 'booted' but is still internally in the 'Booting' state. This causes app launch to fail with: 'Unable to lookup in current state: Booting' 'simctl returned exit code 149' This fix adds WaitForBootComplete() which uses 'simctl bootstatus' to block until the simulator is fully booted before attempting to run tests. Fixes integration test failures on iOS 26.2 / Xcode 26.
There was a problem hiding this comment.
Pull request overview
This PR fixes iOS integration test failures caused by a race condition where the simulator reports as "booted" but is still in the internal "Booting" state, causing app launch failures with error code 405.
Changes:
- Added
Simulator.WaitForBootComplete()method that usessimctl bootstatusto block until the simulator is fully booted - Updated
IOSSimulatorFixtureto callWaitForBootComplete()after launching the simulator
Reviewed changes
Copilot reviewed 2 out of 2 changed files in this pull request and generated 2 comments.
| File | Description |
|---|---|
src/TestUtils/src/Microsoft.Maui.IntegrationTests/Apple/Simulator.cs |
Added WaitForBootComplete() method with 120-second timeout that uses simctl bootstatus to wait for full boot completion |
src/TestUtils/src/Microsoft.Maui.IntegrationTests/AppleTemplateTests.cs |
Updated IOSSimulatorFixture constructor to call WaitForBootComplete() after Launch() with explanatory comments |
| // Wait for simulator to fully boot to avoid race condition where | ||
| // simulator reports "booted" but is still in Booting state internally | ||
| // This prevents "Unable to lookup in current state: Booting" errors | ||
| TestSimulator.WaitForBootComplete(); |
There was a problem hiding this comment.
The return value of WaitForBootComplete() is not checked. If the simulator fails to fully boot (returns false), tests will proceed anyway and likely fail with the same race condition error. Consider checking the return value and throwing an exception or logging a clear error if the boot wait fails, so that test failures are more obvious and attributed to the correct cause.
… names 1. Add exception throw if WaitForBootComplete() fails to prevent silently proceeding with an unready simulator 2. Use job.name instead of testIdentifier + pool.label for artifact names to prevent conflicts when multiple jobs (ARM64 and MacOSPool lanes) run the same test with the same pool label on main branch builds
This is a temporary change to run both ARM64 and MacOSPool lanes on PR to verify the artifact naming fix works correctly. Will revert after validation.
The artifact naming fix has been validated - both ARM64 and MacOSPool lanes successfully created unique artifacts without collision.
- Add arch: ARM64 to all ARM64 iOS test jobs - Add arch: x64 to all x64 iOS test jobs - Update artifact and test result names to include arch - TEMPORARY: Enable x64 lanes for PR validation
|
/azp run |
|
Azure Pipelines successfully started running 3 pipeline(s). |
All 12 iOS integration tests passed with unique artifact names: - ARM64 variants: 6 artifacts - x64 variants: 6 artifacts No artifact naming collisions. Fix validated.
Jobs will now show: - RunOniOS_MauiDebug ARM64 - RunOniOS_MauiDebug x64 Instead of both showing 'RunOniOS_MauiDebug macOS'
|
/azp run |
|
Azure Pipelines successfully started running 3 pipeline(s). |
Validated in build 1279829: - All 12 iOS jobs passed - Job names now show ARM64/x64 correctly - Artifact names are unique (no collisions)
The artifact and test run names were colliding when multiple jobs
had the same testCategory but different platforms (Windows vs macOS).
Changed from:
- 'Integration Tests - $(testIdentifier) ${{ coalesce(job.arch, '') }}'
To:
- 'Integration Tests - ${{ job.name }}'
This ensures each job gets a unique artifact name since job.name
is always unique (e.g., win_buildtemplate_tests, mac_buildtemplate_tests).
Note
Are you waiting for the changes in this PR to be merged?
It would be very helpful if you could test the resulting artifacts from this PR and let us know in a comment if this change resolves your issue. Thank you!
Description
Fixes iOS integration test failures that have been occurring since Jan 23, 2026 on the
mainbranch.Root Cause
When launching iOS apps via XHarness/mlaunch, a race condition occurs where the simulator reports as "booted" but is still internally in the "Booting" state. This causes app launch to fail with:
Fix
This PR adds a
WaitForBootComplete()method to theSimulatorclass which usessimctl bootstatusto block until the simulator is fully booted before attempting to run tests. TheIOSSimulatorFixturenow calls this method after launching the simulator.Affected Tests
RunOniOS_MauiDebugRunOniOS_MauiReleaseRunOniOS_MauiReleaseTrimFullRunOniOS_BlazorDebugRunOniOS_BlazorReleaseRunOniOS_MauiNativeAOTChanges
Simulator.WaitForBootComplete()method inApple/Simulator.csIOSSimulatorFixtureconstructor to callWaitForBootComplete()afterLaunch()