114 lines
3.4 KiB
JavaScript
114 lines
3.4 KiB
JavaScript
import log from '../logger';
|
|
import { waitForCondition } from 'asyncbox';
|
|
|
|
|
|
const commands = {};
|
|
|
|
/**
|
|
* @typedef {Object} BootMonitorOptions
|
|
* @property {?number} timeout [240000] - Simulator booting timeout in ms.
|
|
* @property {?Function} onWaitingDataMigration - This event is fired when data migration stage starts.
|
|
* @property {?Function} onWaitingSystemApp - This event is fired when system app wait stage starts.
|
|
* @property {?Function} onFinished - This event is fired when Simulator is fully booted.
|
|
* @property {?Function} onError - This event is fired when there was an error while monitoring the booting process
|
|
* or when the timeout has expired.
|
|
* @property {?boolean} shouldPreboot [false] Whether to preboot the Simulator
|
|
* if this command is called and it is not already in booted or booting state.
|
|
*/
|
|
|
|
/**
|
|
* Start monitoring for boot status of the particular Simulator.
|
|
* If onFinished property is not set then the method will block
|
|
* until Simulator booting is completed.
|
|
* The method is only available since Xcode8.
|
|
*
|
|
* @param {?BootMonitorOptions} opts - Monitoring options.
|
|
* @returns {SubProcess} The instance of the corresponding monitoring process.
|
|
* @throws {Error} If the Simulator fails to finish booting within the given timeout and onFinished
|
|
* property is not set.
|
|
* @throws {Error} If the `udid` instance property is unset
|
|
*/
|
|
commands.startBootMonitor = async function startBootMonitor (opts = {}) {
|
|
const {
|
|
timeout = 240000,
|
|
onWaitingDataMigration,
|
|
onWaitingSystemApp,
|
|
onFinished,
|
|
onError,
|
|
shouldPreboot,
|
|
} = opts;
|
|
const udid = this.requireUdid('bootstatus');
|
|
|
|
let status = '';
|
|
let isBootingFinished = false;
|
|
let error = null;
|
|
let timeoutHandler = null;
|
|
const args = [udid];
|
|
if (shouldPreboot) {
|
|
args.push('-b');
|
|
}
|
|
const bootMonitor = await this.exec('bootstatus', {
|
|
args,
|
|
asynchronous: true,
|
|
});
|
|
bootMonitor.on('output', (stdout, stderr) => {
|
|
status += stdout || stderr;
|
|
if (stdout) {
|
|
if (stdout.includes('Waiting on Data Migration') && onWaitingDataMigration) {
|
|
onWaitingDataMigration();
|
|
} else if (stdout.includes('Waiting on System App') && onWaitingSystemApp) {
|
|
onWaitingSystemApp();
|
|
}
|
|
}
|
|
});
|
|
bootMonitor.on('exit', (code, signal) => {
|
|
if (timeoutHandler) {
|
|
clearTimeout(timeoutHandler);
|
|
}
|
|
if (code === 0) {
|
|
if (onFinished) {
|
|
onFinished();
|
|
}
|
|
isBootingFinished = true;
|
|
} else {
|
|
status = status || signal;
|
|
error = new Error(status);
|
|
if (onError) {
|
|
onError(error);
|
|
}
|
|
}
|
|
});
|
|
await bootMonitor.start(0);
|
|
const stopMonitor = async () => {
|
|
if (bootMonitor.isRunning) {
|
|
try {
|
|
await bootMonitor.stop();
|
|
} catch (e) {
|
|
log.warn(e.message);
|
|
}
|
|
}
|
|
};
|
|
const start = process.hrtime();
|
|
if (onFinished) {
|
|
timeoutHandler = setTimeout(stopMonitor, timeout);
|
|
} else {
|
|
try {
|
|
await waitForCondition(() => {
|
|
if (error) {
|
|
throw error;
|
|
}
|
|
return isBootingFinished;
|
|
}, {waitMs: timeout, intervalMs: 500});
|
|
} catch (err) {
|
|
await stopMonitor();
|
|
const [seconds] = process.hrtime(start);
|
|
throw new Error(
|
|
`The simulator ${udid} has failed to finish booting after ${seconds}s. ` +
|
|
`Original status: ${status}`);
|
|
}
|
|
}
|
|
return bootMonitor;
|
|
};
|
|
|
|
export default commands;
|