Skip to content

Commit 5fa3615

Browse files
Abbondanzofacebook-github-bot
authored andcommitted
Harden iOS Maestro E2E harness against driver-startup hangs
Summary: iOS Maestro E2E jobs intermittently fail with `spawnSync /bin/sh ETIMEDOUT` (status 143) and zero Maestro output: Maestro never connects to the simulator driver, so every retry burns the full 10-minute `execSync` timeout before being SIGTERM'd. This change resolves the simulator UDID up front by name (and fails fast with a clear message if no matching device exists) instead of scraping the booted list after an in-flight boot Changelog: [Internal] Differential Revision: D109742688
1 parent a54b04e commit 5fa3615

1 file changed

Lines changed: 33 additions & 18 deletions

File tree

.github/workflow-scripts/maestro-ios.js

Lines changed: 33 additions & 18 deletions
Original file line numberDiff line numberDiff line change
@@ -38,30 +38,43 @@ const WORKING_DIRECTORY = args[5];
3838

3939
const MAX_ATTEMPTS = 5;
4040

41-
function launchSimulator(simulatorName) {
42-
console.log(`Launching simulator ${simulatorName}`);
41+
function resolveSimulatorUDID(simulatorName) {
42+
console.log(`Resolving UDID for simulator "${simulatorName}"`);
43+
// Resolve by name (not from the booted list) so we target a specific device
44+
// even before it has finished booting.
45+
const command = `xcrun simctl list devices available -j | jq -r '[.devices[][] | select(.name == "${simulatorName}")] | first | .udid'`;
46+
const udid = String(childProcess.execSync(command)).trim();
47+
if (udid === '' || udid === 'null') {
48+
throw new Error(
49+
`Could not resolve a UDID for a simulator named "${simulatorName}". ` +
50+
'Is the device available on this runner?',
51+
);
52+
}
53+
console.log(`UDID is ${udid}`);
54+
return udid;
55+
}
56+
57+
function launchSimulator(udid) {
58+
console.log(`Booting simulator ${udid}`);
4359
try {
44-
childProcess.execSync(`xcrun simctl boot "${simulatorName}"`);
60+
childProcess.execSync(`xcrun simctl boot "${udid}"`);
4561
} catch (error) {
4662
if (
4763
!error.message.includes('Unable to boot device in current state: Booted')
4864
) {
4965
throw error;
5066
}
5167
}
68+
// `simctl boot` returns as soon as boot is *initiated*. Block until the device
69+
// is fully booted so install/launch/Maestro don't race a half-booted
70+
// simulator, which is the usual cause of Maestro hanging on driver startup.
71+
console.log('Waiting for the simulator to finish booting');
72+
childProcess.execSync(`xcrun simctl bootstatus "${udid}" -b`);
5273
}
5374

54-
function installAppOnSimulator(appPath) {
75+
function installAppOnSimulator(udid, appPath) {
5576
console.log(`Installing app at path ${appPath}`);
56-
childProcess.execSync(`xcrun simctl install booted "${appPath}"`);
57-
}
58-
59-
function extractSimulatorUDID() {
60-
console.log('Retrieving device UDID');
61-
const command = `xcrun simctl list devices booted -j | jq -r '[.devices[]] | add | first | .udid'`;
62-
const udid = String(childProcess.execSync(command)).trim();
63-
console.log(`UDID is ${udid}`);
64-
return udid;
77+
childProcess.execSync(`xcrun simctl install "${udid}" "${appPath}"`);
6578
}
6679

6780
function bringSimulatorInForeground() {
@@ -123,9 +136,11 @@ function executeTestsWithRetries(
123136
const recProcess = startVideoRecording(jsengine, currentAttempt);
124137
try {
125138
const timeout = 1000 * 60 * 10; // 10 minutes
126-
const command = `$HOME/.maestro/bin/maestro --udid="${udid}" test "${maestroFlow}" --format junit -e APP_ID="${appId}"`;
139+
const command = `$HOME/.maestro/bin/maestro --udid="${udid}" test "${maestroFlow}" --format junit --debug-output /tmp/MaestroLogs -e APP_ID="${appId}"`;
127140
console.log(command);
128-
childProcess.execSync(`MAESTRO_DRIVER_STARTUP_TIMEOUT=1500000 ${command}`, {
141+
// Keep the driver-startup budget well under the execSync `timeout` so a
142+
// stuck driver surfaces a real Maestro error instead of a silent SIGTERM.
143+
childProcess.execSync(`MAESTRO_DRIVER_STARTUP_TIMEOUT=180000 ${command}`, {
129144
stdio: 'inherit',
130145
timeout,
131146
});
@@ -163,9 +178,9 @@ async function main() {
163178
console.info('==============================\n');
164179

165180
const simulatorName = 'iPhone 16 Pro';
166-
launchSimulator(simulatorName);
167-
installAppOnSimulator(APP_PATH);
168-
const udid = extractSimulatorUDID();
181+
const udid = resolveSimulatorUDID(simulatorName);
182+
launchSimulator(udid);
183+
installAppOnSimulator(udid, APP_PATH);
169184
bringSimulatorInForeground();
170185
await launchAppOnSimulator(APP_ID, udid, IS_DEBUG);
171186
executeTestsWithRetries(APP_ID, udid, MAESTRO_FLOW, JS_ENGINE, 1);

0 commit comments

Comments
 (0)