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