Unverified Commit e5c286e0 authored by Victoria Ashworth's avatar Victoria Ashworth Committed by GitHub

Upload DerivedData logs in CI (#142643)

When the Dart VM is not found within 10 minutes in CI on CoreDevices (iOS 17+), stop the app and upload the logs from DerivedData. The app has to be stopped first since the logs are not put in DerivedData until it's stopped.

Also, rearranged some logic to have CoreDevice have its own function for Dart VM url discovery.

Debugging for https://github.com/flutter/flutter/issues/142448.
parent 899f4234
...@@ -469,6 +469,7 @@ List<String> _flutterCommandArgs(String command, List<String> options) { ...@@ -469,6 +469,7 @@ List<String> _flutterCommandArgs(String command, List<String> options) {
final String? localEngineHost = localEngineHostFromEnv; final String? localEngineHost = localEngineHostFromEnv;
final String? localEngineSrcPath = localEngineSrcPathFromEnv; final String? localEngineSrcPath = localEngineSrcPathFromEnv;
final String? localWebSdk = localWebSdkFromEnv; final String? localWebSdk = localWebSdkFromEnv;
final bool pubOrPackagesCommand = command.startsWith('packages') || command.startsWith('pub');
return <String>[ return <String>[
command, command,
if (deviceOperatingSystem == DeviceOperatingSystem.ios && supportedDeviceTimeoutCommands.contains(command)) if (deviceOperatingSystem == DeviceOperatingSystem.ios && supportedDeviceTimeoutCommands.contains(command))
...@@ -489,7 +490,9 @@ List<String> _flutterCommandArgs(String command, List<String> options) { ...@@ -489,7 +490,9 @@ List<String> _flutterCommandArgs(String command, List<String> options) {
// Use CI flag when running devicelab tests, except for `packages`/`pub` commands. // Use CI flag when running devicelab tests, except for `packages`/`pub` commands.
// `packages`/`pub` commands effectively runs the `pub` tool, which does not have // `packages`/`pub` commands effectively runs the `pub` tool, which does not have
// the same allowed args. // the same allowed args.
if (!command.startsWith('packages') && !command.startsWith('pub')) '--ci', if (!pubOrPackagesCommand) '--ci',
if (!pubOrPackagesCommand && hostAgent.dumpDirectory != null)
'--debug-logs-dir=${hostAgent.dumpDirectory!.path}'
]; ];
} }
......
...@@ -525,6 +525,7 @@ known, it can be explicitly provided to attach via the command-line, e.g. ...@@ -525,6 +525,7 @@ known, it can be explicitly provided to attach via the command-line, e.g.
devToolsServerAddress: devToolsServerAddress, devToolsServerAddress: devToolsServerAddress,
serveObservatory: serveObservatory, serveObservatory: serveObservatory,
usingCISystem: usingCISystem, usingCISystem: usingCISystem,
debugLogsDirectoryPath: debugLogsDirectoryPath,
); );
return buildInfo.isDebug return buildInfo.isDebug
......
...@@ -264,6 +264,7 @@ abstract class RunCommandBase extends FlutterCommand with DeviceBasedDevelopment ...@@ -264,6 +264,7 @@ abstract class RunCommandBase extends FlutterCommand with DeviceBasedDevelopment
enableDartProfiling: enableDartProfiling, enableDartProfiling: enableDartProfiling,
enableEmbedderApi: enableEmbedderApi, enableEmbedderApi: enableEmbedderApi,
usingCISystem: usingCISystem, usingCISystem: usingCISystem,
debugLogsDirectoryPath: debugLogsDirectoryPath,
); );
} else { } else {
return DebuggingOptions.enabled( return DebuggingOptions.enabled(
...@@ -319,6 +320,7 @@ abstract class RunCommandBase extends FlutterCommand with DeviceBasedDevelopment ...@@ -319,6 +320,7 @@ abstract class RunCommandBase extends FlutterCommand with DeviceBasedDevelopment
enableDartProfiling: enableDartProfiling, enableDartProfiling: enableDartProfiling,
enableEmbedderApi: enableEmbedderApi, enableEmbedderApi: enableEmbedderApi,
usingCISystem: usingCISystem, usingCISystem: usingCISystem,
debugLogsDirectoryPath: debugLogsDirectoryPath,
); );
} }
} }
......
...@@ -364,6 +364,7 @@ class TestCommand extends FlutterCommand with DeviceBasedDevelopmentArtifacts { ...@@ -364,6 +364,7 @@ class TestCommand extends FlutterCommand with DeviceBasedDevelopmentArtifacts {
nullAssertions: boolArg(FlutterOptions.kNullAssertions), nullAssertions: boolArg(FlutterOptions.kNullAssertions),
usingCISystem: usingCISystem, usingCISystem: usingCISystem,
enableImpeller: ImpellerStatus.fromBool(argResults!['enable-impeller'] as bool?), enableImpeller: ImpellerStatus.fromBool(argResults!['enable-impeller'] as bool?),
debugLogsDirectoryPath: debugLogsDirectoryPath,
); );
String? testAssetDirectory; String? testAssetDirectory;
......
...@@ -963,6 +963,7 @@ class DebuggingOptions { ...@@ -963,6 +963,7 @@ class DebuggingOptions {
this.enableDartProfiling = true, this.enableDartProfiling = true,
this.enableEmbedderApi = false, this.enableEmbedderApi = false,
this.usingCISystem = false, this.usingCISystem = false,
this.debugLogsDirectoryPath,
}) : debuggingEnabled = true; }) : debuggingEnabled = true;
DebuggingOptions.disabled(this.buildInfo, { DebuggingOptions.disabled(this.buildInfo, {
...@@ -988,6 +989,7 @@ class DebuggingOptions { ...@@ -988,6 +989,7 @@ class DebuggingOptions {
this.enableDartProfiling = true, this.enableDartProfiling = true,
this.enableEmbedderApi = false, this.enableEmbedderApi = false,
this.usingCISystem = false, this.usingCISystem = false,
this.debugLogsDirectoryPath,
}) : debuggingEnabled = false, }) : debuggingEnabled = false,
useTestFonts = false, useTestFonts = false,
startPaused = false, startPaused = false,
...@@ -1069,6 +1071,7 @@ class DebuggingOptions { ...@@ -1069,6 +1071,7 @@ class DebuggingOptions {
required this.enableDartProfiling, required this.enableDartProfiling,
required this.enableEmbedderApi, required this.enableEmbedderApi,
required this.usingCISystem, required this.usingCISystem,
required this.debugLogsDirectoryPath,
}); });
final bool debuggingEnabled; final bool debuggingEnabled;
...@@ -1112,6 +1115,7 @@ class DebuggingOptions { ...@@ -1112,6 +1115,7 @@ class DebuggingOptions {
final bool enableDartProfiling; final bool enableDartProfiling;
final bool enableEmbedderApi; final bool enableEmbedderApi;
final bool usingCISystem; final bool usingCISystem;
final String? debugLogsDirectoryPath;
/// Whether the tool should try to uninstall a previously installed version of the app. /// Whether the tool should try to uninstall a previously installed version of the app.
/// ///
...@@ -1258,6 +1262,7 @@ class DebuggingOptions { ...@@ -1258,6 +1262,7 @@ class DebuggingOptions {
'enableDartProfiling': enableDartProfiling, 'enableDartProfiling': enableDartProfiling,
'enableEmbedderApi': enableEmbedderApi, 'enableEmbedderApi': enableEmbedderApi,
'usingCISystem': usingCISystem, 'usingCISystem': usingCISystem,
'debugLogsDirectoryPath': debugLogsDirectoryPath,
}; };
static DebuggingOptions fromJson(Map<String, Object?> json, BuildInfo buildInfo) => static DebuggingOptions fromJson(Map<String, Object?> json, BuildInfo buildInfo) =>
...@@ -1313,6 +1318,7 @@ class DebuggingOptions { ...@@ -1313,6 +1318,7 @@ class DebuggingOptions {
enableDartProfiling: (json['enableDartProfiling'] as bool?) ?? true, enableDartProfiling: (json['enableDartProfiling'] as bool?) ?? true,
enableEmbedderApi: (json['enableEmbedderApi'] as bool?) ?? false, enableEmbedderApi: (json['enableEmbedderApi'] as bool?) ?? false,
usingCISystem: (json['usingCISystem'] as bool?) ?? false, usingCISystem: (json['usingCISystem'] as bool?) ?? false,
debugLogsDirectoryPath: json['debugLogsDirectoryPath'] as String?,
); );
} }
......
...@@ -620,105 +620,75 @@ class IOSDevice extends Device { ...@@ -620,105 +620,75 @@ class IOSDevice extends Device {
}); });
Uri? localUri; Uri? localUri;
if (isWirelesslyConnected) { if (isCoreDevice || forceXcodeDebugWorkflow) {
// When using a CoreDevice, device logs are unavailable and therefore localUri = await _discoverDartVMForCoreDevice(
// cannot be used to get the Dart VM url. Instead, get the Dart VM debuggingOptions: debuggingOptions,
// Service by finding services matching the app bundle id and the packageId: packageId,
// device name. ipv6: ipv6,
// vmServiceDiscovery: vmServiceDiscovery,
// If not using a CoreDevice, wait for the Dart VM url to be discovered );
// via logs and then get the Dart VM Service by finding services matching } else if (isWirelesslyConnected) {
// the app bundle id and the Dart VM port. // Wait for the Dart VM url to be discovered via logs (from `ios-deploy`)
// // in ProtocolDiscovery. Then via mDNS, construct the Dart VM url using
// Then in both cases, get the device IP from the Dart VM Service to // the device IP as the host by finding Dart VM services matching the
// construct the Dart VM url using the device IP as the host. // app bundle id and Dart VM port.
if (isCoreDevice) {
localUri = await MDnsVmServiceDiscovery.instance!.getVMServiceUriForLaunch( // Wait for Dart VM Service to start up.
packageId, final Uri? serviceURL = await vmServiceDiscovery?.uri;
this, if (serviceURL == null) {
usesIpv6: ipv6, await iosDeployDebugger?.stopAndDumpBacktrace();
useDeviceIPAsHost: true, await dispose();
); return LaunchResult.failed();
} else { }
// Wait for Dart VM Service to start up.
final Uri? serviceURL = await vmServiceDiscovery?.uri;
if (serviceURL == null) {
await iosDeployDebugger?.stopAndDumpBacktrace();
await dispose();
return LaunchResult.failed();
}
// If Dart VM Service URL with the device IP is not found within 5 seconds, // If Dart VM Service URL with the device IP is not found within 5 seconds,
// change the status message to prompt users to click Allow. Wait 5 seconds because it // change the status message to prompt users to click Allow. Wait 5 seconds because it
// should only show this message if they have not already approved the permissions. // should only show this message if they have not already approved the permissions.
// MDnsVmServiceDiscovery usually takes less than 5 seconds to find it. // MDnsVmServiceDiscovery usually takes less than 5 seconds to find it.
final Timer mDNSLookupTimer = Timer(const Duration(seconds: 5), () { final Timer mDNSLookupTimer = Timer(const Duration(seconds: 5), () {
startAppStatus.stop(); startAppStatus.stop();
startAppStatus = _logger.startProgress( startAppStatus = _logger.startProgress(
'Waiting for approval of local network permissions...', 'Waiting for approval of local network permissions...',
);
});
// Get Dart VM Service URL with the device IP as the host.
localUri = await MDnsVmServiceDiscovery.instance!.getVMServiceUriForLaunch(
packageId,
this,
usesIpv6: ipv6,
deviceVmservicePort: serviceURL.port,
useDeviceIPAsHost: true,
); );
});
// Get Dart VM Service URL with the device IP as the host.
localUri = await MDnsVmServiceDiscovery.instance!.getVMServiceUriForLaunch(
packageId,
this,
usesIpv6: ipv6,
deviceVmservicePort: serviceURL.port,
useDeviceIPAsHost: true,
);
mDNSLookupTimer.cancel(); mDNSLookupTimer.cancel();
}
} else { } else {
if ((isCoreDevice || forceXcodeDebugWorkflow) && vmServiceDiscovery != null) { localUri = await vmServiceDiscovery?.uri;
// When searching for the Dart VM url, search for it via ProtocolDiscovery // If the `ios-deploy` debugger loses connection before it finds the
// (device logs) and mDNS simultaneously, since both can be flaky at times. // Dart Service VM url, try starting the debugger and launching the
final Future<Uri?> vmUrlFromMDns = MDnsVmServiceDiscovery.instance!.getVMServiceUriForLaunch( // app again.
packageId, if (localUri == null &&
this, debuggingOptions.usingCISystem &&
usesIpv6: ipv6, iosDeployDebugger != null &&
); iosDeployDebugger!.lostConnection) {
final Future<Uri?> vmUrlFromLogs = vmServiceDiscovery.uri; _logger.printStatus('Lost connection to device. Trying to connect again...');
localUri = await Future.any( await dispose();
<Future<Uri?>>[vmUrlFromMDns, vmUrlFromLogs] vmServiceDiscovery = _setupDebuggerAndVmServiceDiscovery(
package: package,
bundle: bundle,
debuggingOptions: debuggingOptions,
launchArguments: launchArguments,
ipv6: ipv6,
uninstallFirst: false,
skipInstall: true,
); );
installationResult = await iosDeployDebugger!.launchAndAttach() ? 0 : 1;
// If the first future to return is null, wait for the other to complete. if (installationResult != 0) {
if (localUri == null) { _printInstallError(bundle);
final List<Uri?> vmUrls = await Future.wait(
<Future<Uri?>>[vmUrlFromMDns, vmUrlFromLogs]
);
localUri = vmUrls.where((Uri? vmUrl) => vmUrl != null).firstOrNull;
}
} else {
localUri = await vmServiceDiscovery?.uri;
// If the `ios-deploy` debugger loses connection before it finds the
// Dart Service VM url, try starting the debugger and launching the
// app again.
if (localUri == null &&
debuggingOptions.usingCISystem &&
iosDeployDebugger != null &&
iosDeployDebugger!.lostConnection) {
_logger.printStatus('Lost connection to device. Trying to connect again...');
await dispose(); await dispose();
vmServiceDiscovery = _setupDebuggerAndVmServiceDiscovery( return LaunchResult.failed();
package: package,
bundle: bundle,
debuggingOptions: debuggingOptions,
launchArguments: launchArguments,
ipv6: ipv6,
uninstallFirst: false,
skipInstall: true,
);
installationResult = await iosDeployDebugger!.launchAndAttach() ? 0 : 1;
if (installationResult != 0) {
_printInstallError(bundle);
await dispose();
return LaunchResult.failed();
}
localUri = await vmServiceDiscovery.uri;
} }
localUri = await vmServiceDiscovery.uri;
} }
} }
timer.cancel(); timer.cancel();
...@@ -757,6 +727,96 @@ class IOSDevice extends Device { ...@@ -757,6 +727,96 @@ class IOSDevice extends Device {
_logger.printError(''); _logger.printError('');
} }
/// Find the Dart VM url using ProtocolDiscovery (logs from `idevicesyslog`)
/// and mDNS simultaneously, using whichever is found first. `idevicesyslog`
/// does not work on wireless devices, so only use mDNS for wireless devices.
/// Wireless devices require using the device IP as the host.
Future<Uri?> _discoverDartVMForCoreDevice({
required String packageId,
required bool ipv6,
required DebuggingOptions debuggingOptions,
ProtocolDiscovery? vmServiceDiscovery,
}) async {
Timer? maxWaitForCI;
final Completer<Uri?> cancelCompleter = Completer<Uri?>();
// When testing in CI, wait a max of 10 minutes for the Dart VM to be found.
// Afterwards, stop the app from running and upload DerivedData Logs to debug
// logs directory. CoreDevices are run through Xcode and launch logs are
// therefore found in DerivedData.
if (debuggingOptions.usingCISystem && debuggingOptions.debugLogsDirectoryPath != null) {
maxWaitForCI = Timer(const Duration(minutes: 10), () async {
_logger.printError('Failed to find Dart VM after 10 minutes.');
await _xcodeDebug.exit();
final String? homePath = _platform.environment['HOME'];
Directory? derivedData;
if (homePath != null) {
derivedData = _fileSystem.directory(
_fileSystem.path.join(homePath, 'Library', 'Developer', 'Xcode', 'DerivedData'),
);
}
if (derivedData != null && derivedData.existsSync()) {
final Directory debugLogsDirectory = _fileSystem.directory(
debuggingOptions.debugLogsDirectoryPath,
);
debugLogsDirectory.createSync(recursive: true);
for (final FileSystemEntity entity in derivedData.listSync()) {
if (entity is! Directory || !entity.childDirectory('Logs').existsSync()) {
continue;
}
final Directory logsToCopy = entity.childDirectory('Logs');
final Directory copyDestination = debugLogsDirectory
.childDirectory('DerivedDataLogs')
.childDirectory(entity.basename)
.childDirectory('Logs');
_logger.printTrace('Copying logs ${logsToCopy.path} to ${copyDestination.path}...');
copyDirectory(logsToCopy, copyDestination);
}
}
cancelCompleter.complete();
});
}
final Future<Uri?> vmUrlFromMDns = MDnsVmServiceDiscovery.instance!.getVMServiceUriForLaunch(
packageId,
this,
usesIpv6: ipv6,
useDeviceIPAsHost: isWirelesslyConnected,
);
final List<Future<Uri?>> discoveryOptions = <Future<Uri?>>[
vmUrlFromMDns,
];
// vmServiceDiscovery uses device logs (`idevicesyslog`), which doesn't work
// on wireless devices.
if (vmServiceDiscovery != null && !isWirelesslyConnected) {
final Future<Uri?> vmUrlFromLogs = vmServiceDiscovery.uri;
discoveryOptions.add(vmUrlFromLogs);
}
Uri? localUri = await Future.any(
<Future<Uri?>>[...discoveryOptions, cancelCompleter.future],
);
// If the first future to return is null, wait for the other to complete
// unless canceled.
if (localUri == null && !cancelCompleter.isCompleted) {
final Future<List<Uri?>> allDiscoveryOptionsComplete = Future.wait(discoveryOptions);
await Future.any(<Future<Object?>>[
allDiscoveryOptionsComplete,
cancelCompleter.future,
]);
if (!cancelCompleter.isCompleted) {
// If it wasn't cancelled, that means one of the discovery options completed.
final List<Uri?> vmUrls = await allDiscoveryOptionsComplete;
localUri = vmUrls.where((Uri? vmUrl) => vmUrl != null).firstOrNull;
}
}
maxWaitForCI?.cancel();
return localUri;
}
ProtocolDiscovery _setupDebuggerAndVmServiceDiscovery({ ProtocolDiscovery _setupDebuggerAndVmServiceDiscovery({
required IOSApp package, required IOSApp package,
required Directory bundle, required Directory bundle,
......
...@@ -377,6 +377,8 @@ abstract class FlutterCommand extends Command<void> { ...@@ -377,6 +377,8 @@ abstract class FlutterCommand extends Command<void> {
/// Whether flutter is being run from our CI. /// Whether flutter is being run from our CI.
bool get usingCISystem => boolArg(FlutterGlobalOptions.kContinuousIntegrationFlag, global: true); bool get usingCISystem => boolArg(FlutterGlobalOptions.kContinuousIntegrationFlag, global: true);
String? get debugLogsDirectoryPath => stringArg(FlutterGlobalOptions.kDebugLogsDirectoryFlag, global: true);
/// The value of the `--filesystem-scheme` argument. /// The value of the `--filesystem-scheme` argument.
/// ///
/// This can be overridden by some of its subclasses. /// This can be overridden by some of its subclasses.
......
...@@ -44,6 +44,7 @@ abstract final class FlutterGlobalOptions { ...@@ -44,6 +44,7 @@ abstract final class FlutterGlobalOptions {
static const String kVersionFlag = 'version'; static const String kVersionFlag = 'version';
static const String kWrapColumnOption = 'wrap-column'; static const String kWrapColumnOption = 'wrap-column';
static const String kWrapFlag = 'wrap'; static const String kWrapFlag = 'wrap';
static const String kDebugLogsDirectoryFlag = 'debug-logs-dir';
} }
class FlutterCommandRunner extends CommandRunner<void> { class FlutterCommandRunner extends CommandRunner<void> {
...@@ -164,6 +165,11 @@ class FlutterCommandRunner extends CommandRunner<void> { ...@@ -164,6 +165,11 @@ class FlutterCommandRunner extends CommandRunner<void> {
help: 'Enable a set of CI-specific test debug settings.', help: 'Enable a set of CI-specific test debug settings.',
hide: !verboseHelp, hide: !verboseHelp,
); );
argParser.addOption(
FlutterGlobalOptions.kDebugLogsDirectoryFlag,
help: 'Path to a directory where logs for debugging may be added.',
hide: !verboseHelp,
);
} }
@override @override
......
...@@ -427,6 +427,7 @@ void main() { ...@@ -427,6 +427,7 @@ void main() {
'--skia-deterministic-rendering', '--skia-deterministic-rendering',
'--enable-embedder-api', '--enable-embedder-api',
'--ci', '--ci',
'--debug-logs-dir=path/to/logs'
]), throwsToolExit()); ]), throwsToolExit());
final DebuggingOptions options = await command.createDebuggingOptions(false); final DebuggingOptions options = await command.createDebuggingOptions(false);
...@@ -444,6 +445,7 @@ void main() { ...@@ -444,6 +445,7 @@ void main() {
expect(options.enableSoftwareRendering, true); expect(options.enableSoftwareRendering, true);
expect(options.skiaDeterministicRendering, true); expect(options.skiaDeterministicRendering, true);
expect(options.usingCISystem, true); expect(options.usingCISystem, true);
expect(options.debugLogsDirectoryPath, 'path/to/logs');
}, overrides: <Type, Generator>{ }, overrides: <Type, Generator>{
Cache: () => Cache.test(processManager: FakeProcessManager.any()), Cache: () => Cache.test(processManager: FakeProcessManager.any()),
FileSystem: () => MemoryFileSystem.test(), FileSystem: () => MemoryFileSystem.test(),
......
...@@ -1262,6 +1262,7 @@ void main() { ...@@ -1262,6 +1262,7 @@ void main() {
'--skia-deterministic-rendering', '--skia-deterministic-rendering',
'--enable-embedder-api', '--enable-embedder-api',
'--ci', '--ci',
'--debug-logs-dir=path/to/logs'
]), throwsToolExit()); ]), throwsToolExit());
final DebuggingOptions options = await command.createDebuggingOptions(false); final DebuggingOptions options = await command.createDebuggingOptions(false);
...@@ -1281,6 +1282,7 @@ void main() { ...@@ -1281,6 +1282,7 @@ void main() {
expect(options.enableSoftwareRendering, true); expect(options.enableSoftwareRendering, true);
expect(options.skiaDeterministicRendering, true); expect(options.skiaDeterministicRendering, true);
expect(options.usingCISystem, true); expect(options.usingCISystem, true);
expect(options.debugLogsDirectoryPath, 'path/to/logs');
}, overrides: <Type, Generator>{ }, overrides: <Type, Generator>{
Cache: () => Cache.test(processManager: FakeProcessManager.any()), Cache: () => Cache.test(processManager: FakeProcessManager.any()),
FileSystem: () => MemoryFileSystem.test(), FileSystem: () => MemoryFileSystem.test(),
......
...@@ -966,6 +966,78 @@ void main() { ...@@ -966,6 +966,78 @@ void main() {
MDnsVmServiceDiscovery: () => mdnsDiscovery, MDnsVmServiceDiscovery: () => mdnsDiscovery,
}); });
}); });
testUsingContext('IOSDevice.startApp fails to find Dart VM in CI', () async {
final FileSystem fileSystem = MemoryFileSystem.test();
final FakeProcessManager processManager = FakeProcessManager.empty();
const String pathToFlutterLogs = '/path/to/flutter/logs';
const String pathToHome = '/path/to/home';
final Directory temporaryXcodeProjectDirectory = fileSystem.systemTempDirectory.childDirectory('flutter_empty_xcode.rand0');
final Directory bundleLocation = fileSystem.currentDirectory;
final IOSDevice device = setUpIOSDevice(
processManager: processManager,
fileSystem: fileSystem,
isCoreDevice: true,
coreDeviceControl: FakeIOSCoreDeviceControl(),
xcodeDebug: FakeXcodeDebug(
expectedProject: XcodeDebugProject(
scheme: 'Runner',
xcodeWorkspace: temporaryXcodeProjectDirectory.childDirectory('Runner.xcworkspace'),
xcodeProject: temporaryXcodeProjectDirectory.childDirectory('Runner.xcodeproj'),
hostAppProjectName: 'Runner',
),
expectedDeviceId: '123',
expectedLaunchArguments: <String>['--enable-dart-profiling'],
expectedBundlePath: bundleLocation.path,
),
platform: FakePlatform(
operatingSystem: 'macos',
environment: <String, String>{
'HOME': pathToHome,
},
),
);
final IOSApp iosApp = PrebuiltIOSApp(
projectBundleId: 'app',
bundleName: 'Runner',
uncompressedBundle: bundleLocation,
applicationPackage: bundleLocation,
);
final FakeDeviceLogReader deviceLogReader = FakeDeviceLogReader();
device.portForwarder = const NoOpDevicePortForwarder();
device.setLogReader(iosApp, deviceLogReader);
const String projectLogsPath = 'Runner-project1/Logs/Launch/Runner.xcresults';
fileSystem.directory('$pathToHome/Library/Developer/Xcode/DerivedData/$projectLogsPath').createSync(recursive: true);
final Completer<void> completer = Completer<void>();
await FakeAsync().run((FakeAsync time) {
final Future<LaunchResult> futureLaunchResult = device.startApp(iosApp,
prebuiltApplication: true,
debuggingOptions: DebuggingOptions.enabled(
BuildInfo.debug,
usingCISystem: true,
debugLogsDirectoryPath: pathToFlutterLogs,
),
platformArgs: <String, dynamic>{},
);
futureLaunchResult.then((LaunchResult launchResult) {
expect(launchResult.started, false);
expect(launchResult.hasVmService, false);
expect(fileSystem.directory('$pathToFlutterLogs/DerivedDataLogs/$projectLogsPath').existsSync(), true);
completer.complete();
});
time.elapse(const Duration(minutes: 15));
time.flushMicrotasks();
return completer.future;
});
}, overrides: <Type, Generator>{
MDnsVmServiceDiscovery: () => FakeMDnsVmServiceDiscovery(returnsNull: true),
});
}); });
}); });
} }
...@@ -980,9 +1052,10 @@ IOSDevice setUpIOSDevice({ ...@@ -980,9 +1052,10 @@ IOSDevice setUpIOSDevice({
bool isCoreDevice = false, bool isCoreDevice = false,
IOSCoreDeviceControl? coreDeviceControl, IOSCoreDeviceControl? coreDeviceControl,
FakeXcodeDebug? xcodeDebug, FakeXcodeDebug? xcodeDebug,
FakePlatform? platform,
}) { }) {
final Artifacts artifacts = Artifacts.test(); final Artifacts artifacts = Artifacts.test();
final FakePlatform macPlatform = FakePlatform( final FakePlatform macPlatform = platform ?? FakePlatform(
operatingSystem: 'macos', operatingSystem: 'macos',
environment: <String, String>{}, environment: <String, String>{},
); );
......
Markdown is supported
0% or
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment