Skip to content

Fix iOS integration test simulator boot race condition#33884

Merged
PureWeen merged 12 commits intomainfrom
fix/integration-test-simulator-boot-race
Feb 5, 2026
Merged

Fix iOS integration test simulator boot race condition#33884
PureWeen merged 12 commits intomainfrom
fix/integration-test-simulator-boot-race

Conversation

@PureWeen
Copy link
Member

@PureWeen PureWeen commented Feb 3, 2026

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 main branch.

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:

An error was encountered processing the command (domain=com.apple.CoreSimulator.SimError, code=405):
Unable to lookup in current state: Booting

error HE0042: Could not launch the app on the device: simctl returned exit code 149

Fix

This PR adds a WaitForBootComplete() method to the Simulator class which uses simctl bootstatus to block until the simulator is fully booted before attempting to run tests. The IOSSimulatorFixture now calls this method after launching the simulator.

Affected Tests

  • RunOniOS_MauiDebug
  • RunOniOS_MauiRelease
  • RunOniOS_MauiReleaseTrimFull
  • RunOniOS_BlazorDebug
  • RunOniOS_BlazorRelease
  • RunOniOS_MauiNativeAOT

Changes

  • Added Simulator.WaitForBootComplete() method in Apple/Simulator.cs
  • Updated IOSSimulatorFixture constructor to call WaitForBootComplete() after Launch()

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.
Copilot AI review requested due to automatic review settings February 3, 2026 23:02
Copy link
Contributor

Copilot AI left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

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 uses simctl bootstatus to block until the simulator is fully booted
  • Updated IOSSimulatorFixture to call WaitForBootComplete() 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();
Copy link

Copilot AI Feb 3, 2026

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

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.

Copilot uses AI. Check for mistakes.
… 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
@PureWeen
Copy link
Member Author

PureWeen commented Feb 4, 2026

/azp run

@azure-pipelines
Copy link

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'
@PureWeen
Copy link
Member Author

PureWeen commented Feb 4, 2026

/azp run

@azure-pipelines
Copy link

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).
@PureWeen PureWeen merged commit bd49de4 into main Feb 5, 2026
25 of 28 checks passed
@PureWeen PureWeen deleted the fix/integration-test-simulator-boot-race branch February 5, 2026 02:42
@github-actions github-actions bot locked and limited conversation to collaborators Mar 7, 2026
Sign up for free to subscribe to this conversation on GitHub. Already have an account? Sign in.

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

2 participants