fbxctest/FBXCTestKit/Runners/FBXCTestSimulatorFetcher.m (103 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 "FBXCTestSimulatorFetcher.h" #import <FBSimulatorControl/FBSimulatorControl.h> #import <XCTestBootstrap/XCTestBootstrap.h> #import "FBXCTestCommandLine.h" #import "FBXCTestDestination.h" @interface FBXCTestSimulatorFetcher () @property (nonatomic, strong, readonly) FBSimulatorControl *simulatorControl; @property (nonatomic, strong, readonly) id<FBControlCoreLogger> logger; @end @implementation FBXCTestSimulatorFetcher #pragma mark Initializers + (nullable instancetype)fetcherWithWorkingDirectory:(NSString *)workingDirectory logger:(id<FBControlCoreLogger>)logger error:(NSError **)error { NSString *setPath = [self setPathForWorkingDirectory:workingDirectory logger:logger]; FBSimulatorControlConfiguration *controlConfiguration = [FBSimulatorControlConfiguration configurationWithDeviceSetPath:setPath logger:logger reporter:nil]; NSError *innerError = nil; FBSimulatorControl *simulatorControl = [FBSimulatorControl withConfiguration:controlConfiguration error:&innerError]; if (!simulatorControl) { return [FBXCTestError failWithError:innerError errorOut:error]; } return [[self alloc] initWithSimulatorControl:simulatorControl logger:logger]; } + (NSString *)setPathForWorkingDirectory:(NSString *)workingDirectory logger:(id<FBControlCoreLogger>)logger { NSOperatingSystemVersion xcodeVersion = FBXcodeConfiguration.xcodeVersion; if (xcodeVersion.majorVersion == 11 && xcodeVersion.minorVersion >= 5) { [logger logFormat:@"CoreSimulatorService can wedge with custom sets in Xcode %@, using the default set", FBXcodeConfiguration.xcodeVersionNumber]; return nil; } NSString *fallbackSetPath = [workingDirectory stringByAppendingPathComponent:@"sim"]; NSString *xctestDevicesSet = [NSHomeDirectory() stringByAppendingPathComponent:@"Library/Developer/XCTestDevices"]; BOOL isDirectory = NO; if (![NSFileManager.defaultManager fileExistsAtPath:xctestDevicesSet isDirectory:&isDirectory]) { [logger logFormat:@"%@ is not present. Falling back to using set path relative to working directory %@", xctestDevicesSet, fallbackSetPath]; return fallbackSetPath; } if (!isDirectory) { [logger logFormat:@"%@ is not a directory. Falling back to using set path relative to working directory %@", xctestDevicesSet, fallbackSetPath]; return fallbackSetPath; } [logger logFormat:@"%@ exists, using it for fbxctest's simulator set", xctestDevicesSet]; return xctestDevicesSet; } - (instancetype)initWithSimulatorControl:(FBSimulatorControl *)simulatorControl logger:(id<FBControlCoreLogger>)logger { self = [super init]; if (!self) { return nil; } _simulatorControl = simulatorControl; _logger = logger; return self; } #pragma mark Public Methods - (FBFuture<FBSimulator *> *)fetchSimulatorForCommandLine:(FBXCTestCommandLine *)commandLine { FBXCTestDestinationiPhoneSimulator *destination = (FBXCTestDestinationiPhoneSimulator *) commandLine.destination; if (![destination isKindOfClass:FBXCTestDestinationiPhoneSimulator.class]) { return [[FBXCTestError describeFormat:@"%@ is not a Simulator Destination", destination] failFuture]; } if ([commandLine.configuration isKindOfClass:FBTestManagerTestConfiguration.class]) { return [self fetchSimulatorForApplicationTest:destination]; } return [self fetchSimulatorForLogicTest:destination]; } - (FBFuture<FBSimulator *> *)fetchSimulatorForLogicTest:(FBXCTestDestinationiPhoneSimulator *)destination { FBSimulatorConfiguration *configuration = [FBXCTestSimulatorFetcher configurationForDestination:destination]; return [self.simulatorControl.set createSimulatorWithConfiguration:configuration]; } - (FBFuture<FBSimulator *> *)fetchSimulatorForApplicationTest:(FBXCTestDestinationiPhoneSimulator *)destination { FBSimulatorBootConfiguration *bootConfiguration = [[FBSimulatorBootConfiguration alloc] initWithOptions:(FBSimulatorBootOptionsTieToProcessLifecycle | FBSimulatorBootOptionsVerifyUsable) environment:@{}]; return [[self fetchSimulatorForLogicTest:destination] onQueue:dispatch_get_main_queue() fmap:^(FBSimulator *simulator) { return [[simulator boot:bootConfiguration] mapReplace:simulator]; }]; } - (FBFuture<NSNull *> *)returnSimulator:(FBSimulator *)simulator { return [[self.simulatorControl.set delete:simulator] mapReplace:NSNull.null]; } #pragma mark Private + (FBSimulatorConfiguration *)configurationForDestination:(FBXCTestDestinationiPhoneSimulator *)destination { FBSimulatorConfiguration *configuration = [FBSimulatorConfiguration defaultConfiguration]; if (destination.model) { configuration = [configuration withDeviceModel:destination.model]; } if (destination.version) { configuration = [configuration withOSNamed:destination.version]; } return configuration; } @end