FBSimulatorControl/Strategies/FBSimulatorBootStrategy.m (51 lines of code) (raw):

/* * Copyright (c) Meta Platforms, Inc. and affiliates. * * This source code is licensed under the MIT license found in the * LICENSE file in the root directory of this source tree. */ #import "FBSimulatorBootStrategy.h" #import <CoreSimulator/SimDevice.h> #import <FBControlCore/FBControlCore.h> #import "FBSimulator.h" #import "FBSimulatorError.h" #import "FBSimulatorBootConfiguration.h" #import "FBSimulatorBootVerificationStrategy.h" @implementation FBSimulatorBootStrategy #pragma mark Initializers + (FBFuture<NSNull *> *)boot:(FBSimulator *)simulator withConfiguration:(FBSimulatorBootConfiguration *)configuration { // Return early depending on Simulator state. if (simulator.state == FBiOSTargetStateBooted) { return FBFuture.empty; } if (simulator.state != FBiOSTargetStateShutdown) { return [[FBSimulatorError describeFormat:@"Cannot Boot Simulator when in %@ state", simulator.stateString] failFuture]; } // Boot via CoreSimulator. return [[self performSimulatorBoot:simulator withConfiguration:configuration] onQueue:simulator.workQueue fmap:^(id _) { return [self verifySimulatorIsBooted:simulator withConfiguration:configuration]; }]; } #pragma mark Private + (FBFuture<NSNull *> *)verifySimulatorIsBooted:(FBSimulator *)simulator withConfiguration:(FBSimulatorBootConfiguration *)configuration { // Return early if the option to verify boot is not set.. if ((configuration.options & FBSimulatorBootOptionsVerifyUsable) != FBSimulatorBootOptionsVerifyUsable) { return FBFuture.empty; } // Otherwise actually perform the boot verification. return [FBSimulatorBootVerificationStrategy verifySimulatorIsBooted:simulator]; } + (FBFuture<NSNull *> *)performSimulatorBoot:(FBSimulator *)simulator withConfiguration:(FBSimulatorBootConfiguration *)configuration { // "Persisting" means that the booted Simulator should live beyond the lifecycle of the process that calls the boot API. // The inverse of this is `FBSimulatorBootOptionsTieToProcessLifecycle`, which means that the Simulator should shutdown when the process that calls the boot API dies. // // The default behaviour for `simctl` is to 'persist'; the Simulator is left booted until 'shutdown' is called, even after the simctl process dies. // `simctl` has the option to 'tie to process lifecycle', if the undocumented `--wait` flag is passed after the Simulator's UDID. // // If `FBSimulatorBootOptionsTieToProcessLifecycle` is enabled we *do not* want the Simulator to live beyond the lifecycle of the process calling boot. // This behaviour is useful for automated scenarios, where terminating the process that performs the boot gives us clean teardown semantics, without the need to call 'shutdown'. BOOL persist = (configuration.options & FBSimulatorBootOptionsTieToProcessLifecycle) != FBSimulatorBootOptionsTieToProcessLifecycle; NSDictionary<NSString *, id> * options = @{ @"persist": @(persist), @"env" : configuration.environment ?: @{}, }; FBMutableFuture<NSNull *> *future = FBMutableFuture.future; [simulator.device bootAsyncWithOptions:options completionQueue:simulator.workQueue completionHandler:^(NSError *error){ if (error) { [future resolveWithError:error]; } else { [future resolveWithResult:NSNull.null]; } }]; return future; } @end