Revert "Stream logging from attached debugger on iOS (#66092)" (#66367)
This reverts commit 5c8580360aa6e98c560dfe9191e0d42ad2015f9e.
diff --git a/packages/flutter_tools/lib/src/ios/devices.dart b/packages/flutter_tools/lib/src/ios/devices.dart
index fb7aea5..9bad5a3 100644
--- a/packages/flutter_tools/lib/src/ios/devices.dart
+++ b/packages/flutter_tools/lib/src/ios/devices.dart
@@ -212,9 +212,6 @@
DevicePortForwarder _portForwarder;
- @visibleForTesting
- IOSDeployDebugger iosDeployDebugger;
-
@override
Future<bool> get isLocalEmulator async => false;
@@ -398,38 +395,23 @@
timeout: timeoutConfiguration.slowOperation);
try {
ProtocolDiscovery observatoryDiscovery;
- int installationResult = 1;
if (debuggingOptions.debuggingEnabled) {
_logger.printTrace('Debugging is enabled, connecting to observatory');
- iosDeployDebugger = _iosDeploy.prepareDebuggerForLaunch(
- deviceId: id,
- bundlePath: bundle.path,
- launchArguments: launchArguments,
- interfaceType: interfaceType,
- );
-
- final DeviceLogReader deviceLogReader = getLogReader(app: package);
- if (deviceLogReader is IOSDeviceLogReader) {
- deviceLogReader.debuggerStream = iosDeployDebugger;
- }
observatoryDiscovery = ProtocolDiscovery.observatory(
- deviceLogReader,
+ getLogReader(app: package),
portForwarder: portForwarder,
- throttleDuration: fallbackPollingDelay,
- throttleTimeout: fallbackThrottleTimeout ?? const Duration(seconds: 5),
hostPort: debuggingOptions.hostVmServicePort,
devicePort: debuggingOptions.deviceVmServicePort,
ipv6: ipv6,
- );
- installationResult = await iosDeployDebugger.launchAndAttach() ? 0 : 1;
- } else {
- installationResult = await _iosDeploy.launchApp(
- deviceId: id,
- bundlePath: bundle.path,
- launchArguments: launchArguments,
- interfaceType: interfaceType,
+ throttleTimeout: fallbackThrottleTimeout ?? const Duration(seconds: 1),
);
}
+ final int installationResult = await _iosDeploy.runApp(
+ deviceId: id,
+ bundlePath: bundle.path,
+ launchArguments: launchArguments,
+ interfaceType: interfaceType,
+ );
if (installationResult != 0) {
_logger.printError('Could not run ${bundle.path} on $id.');
_logger.printError('Try launching Xcode and selecting "Product > Run" to fix the problem:');
@@ -483,11 +465,7 @@
IOSApp app, {
String userIdentifier,
}) async {
- // If the debugger is not attached, killing the ios-deploy process won't stop the app.
- if (iosDeployDebugger!= null && iosDeployDebugger.debuggerAttached) {
- // Avoid null.
- return iosDeployDebugger?.exit() == true;
- }
+ // Currently we don't have a way to stop an app running on iOS.
return false;
}
@@ -677,13 +655,6 @@
// Matches a syslog line from any app.
RegExp _anyLineRegex;
- // Logging from native code/Flutter engine is prefixed by timestamp and process metadata:
- // 2020-09-15 19:15:10.931434-0700 Runner[541:226276] Did finish launching.
- // 2020-09-15 19:15:10.931434-0700 Runner[541:226276] [Category] Did finish launching.
- //
- // Logging from the dart code has no prefixing metadata.
- final RegExp _debuggerLoggingRegex = RegExp(r'^\S* \S* \S*\[[0-9:]*] (.*)');
-
StreamController<String> _linesController;
List<StreamSubscription<void>> _loggingSubscriptions;
@@ -716,10 +687,6 @@
}
void logMessage(vm_service.Event event) {
- if (_iosDeployDebugger != null && _iosDeployDebugger.debuggerAttached) {
- // Prefer the more complete logs from the attached debugger.
- return;
- }
final String message = processVmServiceMessage(event);
if (message.isNotEmpty) {
_linesController.add(message);
@@ -732,26 +699,6 @@
]);
}
- /// Log reader will listen to [debugger.logLines] and will detach debugger on dispose.
- set debuggerStream(IOSDeployDebugger debugger) {
- // Logging is gathered from syslog on iOS 13 and earlier.
- if (_majorSdkVersion < _minimumUniversalLoggingSdkVersion) {
- return;
- }
- _iosDeployDebugger = debugger;
- // Add the debugger logs to the controller created on initialization.
- _loggingSubscriptions.add(debugger.logLines.listen(
- (String line) => _linesController.add(_debuggerLineHandler(line)),
- onError: _linesController.addError,
- onDone: _linesController.close,
- cancelOnError: true,
- ));
- }
- IOSDeployDebugger _iosDeployDebugger;
-
- // Strip off the logging metadata (leave the category), or just echo the line.
- String _debuggerLineHandler(String line) => _debuggerLoggingRegex?.firstMatch(line)?.group(1) ?? line;
-
void _listenToSysLog() {
// syslog is not written on iOS 13+.
if (_majorSdkVersion >= _minimumUniversalLoggingSdkVersion) {
@@ -811,7 +758,6 @@
loggingSubscription.cancel();
}
_idevicesyslogProcess?.kill();
- _iosDeployDebugger?.detach();
}
}
diff --git a/packages/flutter_tools/lib/src/ios/fallback_discovery.dart b/packages/flutter_tools/lib/src/ios/fallback_discovery.dart
index 42f337f..56c8147 100644
--- a/packages/flutter_tools/lib/src/ios/fallback_discovery.dart
+++ b/packages/flutter_tools/lib/src/ios/fallback_discovery.dart
@@ -82,29 +82,6 @@
}
try {
- final Uri result = await _protocolDiscovery.uri;
- if (result != null) {
- UsageEvent(
- _kEventName,
- 'log-success',
- flutterUsage: _flutterUsage,
- ).send();
- return result;
- }
- } on ArgumentError {
- // In the event of an invalid InternetAddress, this code attempts to catch
- // an ArgumentError from protocol_discovery.dart
- } on Exception catch (err) {
- _logger.printTrace(err.toString());
- }
- _logger.printTrace('Failed to connect with log scanning, falling back to mDNS');
- UsageEvent(
- _kEventName,
- 'log-failure',
- flutterUsage: _flutterUsage,
- ).send();
-
- try {
final Uri result = await _mDnsObservatoryDiscovery.getObservatoryUri(
packageId,
device,
@@ -122,12 +99,35 @@
} on Exception catch (err) {
_logger.printTrace(err.toString());
}
- _logger.printTrace('Failed to connect with mDNS');
+ _logger.printTrace('Failed to connect with mDNS, falling back to log scanning');
UsageEvent(
_kEventName,
'mdns-failure',
flutterUsage: _flutterUsage,
).send();
+
+ try {
+ final Uri result = await _protocolDiscovery.uri;
+ if (result != null) {
+ UsageEvent(
+ _kEventName,
+ 'fallback-success',
+ flutterUsage: _flutterUsage,
+ ).send();
+ return result;
+ }
+ } on ArgumentError {
+ // In the event of an invalid InternetAddress, this code attempts to catch
+ // an ArgumentError from protocol_discovery.dart
+ } on Exception catch (err) {
+ _logger.printTrace(err.toString());
+ }
+ _logger.printTrace('Failed to connect with log scanning');
+ UsageEvent(
+ _kEventName,
+ 'fallback-failure',
+ flutterUsage: _flutterUsage,
+ ).send();
return null;
}
@@ -148,7 +148,7 @@
assumedWsUri = Uri.parse('ws://localhost:$hostPort/ws');
} on Exception catch (err) {
_logger.printTrace(err.toString());
- _logger.printTrace('Failed to connect directly, falling back to log scanning');
+ _logger.printTrace('Failed to connect directly, falling back to mDNS');
_sendFailureEvent(err, assumedDevicePort);
return null;
}
diff --git a/packages/flutter_tools/lib/src/ios/ios_deploy.dart b/packages/flutter_tools/lib/src/ios/ios_deploy.dart
index 3945bdc..c1e90a7 100644
--- a/packages/flutter_tools/lib/src/ios/ios_deploy.dart
+++ b/packages/flutter_tools/lib/src/ios/ios_deploy.dart
@@ -2,20 +2,15 @@
// Use of this source code is governed by a BSD-style license that can be
// found in the LICENSE file.
-import 'dart:async';
-
import 'package:meta/meta.dart';
import 'package:process/process.dart';
import '../artifacts.dart';
-import '../base/common.dart';
-import '../base/io.dart';
import '../base/logger.dart';
import '../base/platform.dart';
import '../base/process.dart';
import '../build_info.dart';
import '../cache.dart';
-import '../convert.dart';
import 'code_signing.dart';
import 'devices.dart';
@@ -112,47 +107,10 @@
);
}
- /// Returns [IOSDeployDebugger] wrapping attached debugger logic.
- ///
- /// This method does not install the app. Call [IOSDeployDebugger.launchAndAttach()]
- /// to install and attach the debugger to the specified app bundle.
- IOSDeployDebugger prepareDebuggerForLaunch({
- @required String deviceId,
- @required String bundlePath,
- @required List<String> launchArguments,
- @required IOSDeviceInterface interfaceType,
- }) {
- // Interactive debug session to support sending the lldb detach command.
- final List<String> launchCommand = <String>[
- 'script',
- '-t',
- '0',
- '/dev/null',
- _binaryPath,
- '--id',
- deviceId,
- '--bundle',
- bundlePath,
- '--debug',
- if (interfaceType != IOSDeviceInterface.network)
- '--no-wifi',
- if (launchArguments.isNotEmpty) ...<String>[
- '--args',
- launchArguments.join(' '),
- ],
- ];
- return IOSDeployDebugger(
- launchCommand: launchCommand,
- logger: _logger,
- processUtils: _processUtils,
- iosDeployEnv: iosDeployEnv,
- );
- }
-
/// Installs and then runs the specified app bundle.
///
/// Uses ios-deploy and returns the exit code.
- Future<int> launchApp({
+ Future<int> runApp({
@required String deviceId,
@required String bundlePath,
@required List<String> launchArguments,
@@ -211,202 +169,30 @@
return true;
}
- String _monitorFailure(String stdout) => _monitorIOSDeployFailure(stdout, _logger);
-}
-
-/// lldb attach state flow.
-enum _IOSDeployDebuggerState {
- detached,
- launching,
- attached,
-}
-
-/// Wrapper to launch app and attach the debugger with ios-deploy.
-class IOSDeployDebugger {
- IOSDeployDebugger({
- @required Logger logger,
- @required ProcessUtils processUtils,
- @required List<String> launchCommand,
- @required Map<String, String> iosDeployEnv,
- }) : _processUtils = processUtils,
- _logger = logger,
- _launchCommand = launchCommand,
- _iosDeployEnv = iosDeployEnv,
- _debuggerState = _IOSDeployDebuggerState.detached;
-
- /// Create a [IOSDeployDebugger] for testing.
- ///
- /// Sets the command to "ios-deploy" and environment to an empty map.
- @visibleForTesting
- factory IOSDeployDebugger.test({
- @required ProcessManager processManager,
- Logger logger,
- }) {
- final Logger debugLogger = logger ?? BufferLogger.test();
- return IOSDeployDebugger(
- logger: debugLogger,
- processUtils: ProcessUtils(logger: debugLogger, processManager: processManager),
- launchCommand: <String>['ios-deploy'],
- iosDeployEnv: <String, String>{},
- );
- }
-
- final Logger _logger;
- final ProcessUtils _processUtils;
- final List<String> _launchCommand;
- final Map<String, String> _iosDeployEnv;
-
- Process _iosDeployProcess;
-
- Stream<String> get logLines => _debuggerOutput.stream;
- final StreamController<String> _debuggerOutput = StreamController<String>.broadcast();
-
- bool get debuggerAttached => _debuggerState == _IOSDeployDebuggerState.attached;
- _IOSDeployDebuggerState _debuggerState;
-
- // (lldb) run
- // https://github.com/ios-control/ios-deploy/blob/1.11.2-beta.1/src/ios-deploy/ios-deploy.m#L51
- static final RegExp _lldbRun = RegExp(r'\(lldb\)\s*run');
-
- /// Launch the app on the device, and attach the debugger.
- ///
- /// Returns whether or not the debugger successfully attached.
- Future<bool> launchAndAttach() async {
- // Return when the debugger attaches, or the ios-deploy process exits.
- final Completer<bool> debuggerCompleter = Completer<bool>();
- try {
- _iosDeployProcess = await _processUtils.start(
- _launchCommand,
- environment: _iosDeployEnv,
- );
- String lastLineFromDebugger;
- final StreamSubscription<String> stdoutSubscription = _iosDeployProcess.stdout
- .transform<String>(utf8.decoder)
- .transform<String>(const LineSplitter())
- .listen((String line) {
- _monitorIOSDeployFailure(line, _logger);
-
- // (lldb) run
- // success
- // 2020-09-15 13:42:25.185474-0700 Runner[477:181141] flutter: Observatory listening on http://127.0.0.1:57782/
- if (_lldbRun.hasMatch(line)) {
- _logger.printTrace(line);
- _debuggerState = _IOSDeployDebuggerState.launching;
- return;
- }
- // Next line after "run" must be "success", or the attach failed.
- // Example: "error: process launch failed"
- if (_debuggerState == _IOSDeployDebuggerState.launching) {
- _logger.printTrace(line);
- final bool attachSuccess = line == 'success';
- _debuggerState = attachSuccess ? _IOSDeployDebuggerState.attached : _IOSDeployDebuggerState.detached;
- if (!debuggerCompleter.isCompleted) {
- debuggerCompleter.complete(attachSuccess);
- }
- return;
- }
- if (line.contains('PROCESS_STOPPED') ||
- line.contains('PROCESS_EXITED')) {
- // The app exited or crashed, so stop echoing the output.
- // Don't pass any further ios-deploy debugging messages to the log reader after it exits.
- _debuggerState = _IOSDeployDebuggerState.detached;
- _logger.printTrace(line);
- return;
- }
- if (_debuggerState != _IOSDeployDebuggerState.attached) {
- _logger.printTrace(line);
- return;
- }
- if (lastLineFromDebugger != null && lastLineFromDebugger.isNotEmpty && line.isEmpty) {
- // The lldb console stream from ios-deploy is separated lines by an extra \r\n.
- // To avoid all lines being double spaced, if the last line from the
- // debugger was not an empty line, skip this empty line.
- // This will still cause "legit" logged newlines to be doubled...
- } else {
- _debuggerOutput.add(line);
- }
- lastLineFromDebugger = line;
- });
- final StreamSubscription<String> stderrSubscription = _iosDeployProcess.stderr
- .transform<String>(utf8.decoder)
- .transform<String>(const LineSplitter())
- .listen((String line) {
- _monitorIOSDeployFailure(line, _logger);
- _logger.printTrace(line);
- });
- unawaited(_iosDeployProcess.exitCode.then((int status) {
- _logger.printTrace('ios-deploy exited with code $exitCode');
- _debuggerState = _IOSDeployDebuggerState.detached;
- unawaited(stdoutSubscription.cancel());
- unawaited(stderrSubscription.cancel());
- }).whenComplete(() async {
- if (_debuggerOutput.hasListener) {
- // Tell listeners the process died.
- await _debuggerOutput.close();
- }
- if (!debuggerCompleter.isCompleted) {
- debuggerCompleter.complete(false);
- }
- _iosDeployProcess = null;
- }));
- } on ProcessException catch (exception, stackTrace) {
- _logger.printTrace('ios-deploy failed: $exception');
- _debuggerState = _IOSDeployDebuggerState.detached;
- _debuggerOutput.addError(exception, stackTrace);
- } on ArgumentError catch (exception, stackTrace) {
- _logger.printTrace('ios-deploy failed: $exception');
- _debuggerState = _IOSDeployDebuggerState.detached;
- _debuggerOutput.addError(exception, stackTrace);
- }
- // Wait until the debugger attaches, or the attempt fails.
- return debuggerCompleter.future;
- }
-
- bool exit() {
- final bool success = (_iosDeployProcess == null) || _iosDeployProcess.kill();
- _iosDeployProcess = null;
- return success;
- }
-
- void detach() {
- if (!debuggerAttached) {
- return;
- }
-
- try {
- // Detach lldb from the app process.
- _iosDeployProcess?.stdin?.writeln('process detach');
- _debuggerState = _IOSDeployDebuggerState.detached;
- } on SocketException catch (error) {
- // Best effort, try to detach, but maybe the app already exited or already detached.
- _logger.printTrace('Could not detach from debugger: $error');
- }
- }
-}
-
-// Maps stdout line stream. Must return original line.
-String _monitorIOSDeployFailure(String stdout, Logger logger) {
- // Installation issues.
- if (stdout.contains(noProvisioningProfileErrorOne) || stdout.contains(noProvisioningProfileErrorTwo)) {
- logger.printError(noProvisioningProfileInstruction, emphasis: true);
+ // Maps stdout line stream. Must return original line.
+ String _monitorFailure(String stdout) {
+ // Installation issues.
+ if (stdout.contains(noProvisioningProfileErrorOne) || stdout.contains(noProvisioningProfileErrorTwo)) {
+ _logger.printError(noProvisioningProfileInstruction, emphasis: true);
// Launch issues.
- } else if (stdout.contains(deviceLockedError)) {
- logger.printError('''
+ } else if (stdout.contains(deviceLockedError)) {
+ _logger.printError('''
═══════════════════════════════════════════════════════════════════════════════════
Your device is locked. Unlock your device first before running.
═══════════════════════════════════════════════════════════════════════════════════''',
- emphasis: true);
- } else if (stdout.contains(unknownAppLaunchError)) {
- logger.printError('''
+ emphasis: true);
+ } else if (stdout.contains(unknownAppLaunchError)) {
+ _logger.printError('''
═══════════════════════════════════════════════════════════════════════════════════
Error launching app. Try launching from within Xcode via:
open ios/Runner.xcworkspace
Your Xcode version may be too old for your iOS version.
═══════════════════════════════════════════════════════════════════════════════════''',
- emphasis: true);
- }
+ emphasis: true);
+ }
- return stdout;
+ return stdout;
+ }
}
diff --git a/packages/flutter_tools/lib/src/protocol_discovery.dart b/packages/flutter_tools/lib/src/protocol_discovery.dart
index 3d1bc3d..367bccd 100644
--- a/packages/flutter_tools/lib/src/protocol_discovery.dart
+++ b/packages/flutter_tools/lib/src/protocol_discovery.dart
@@ -34,7 +34,7 @@
factory ProtocolDiscovery.observatory(
DeviceLogReader logReader, {
DevicePortForwarder portForwarder,
- Duration throttleDuration,
+ Duration throttleDuration = const Duration(milliseconds: 200),
Duration throttleTimeout,
@required int hostPort,
@required int devicePort,
@@ -45,7 +45,7 @@
logReader,
kObservatoryService,
portForwarder: portForwarder,
- throttleDuration: throttleDuration ?? const Duration(milliseconds: 200),
+ throttleDuration: throttleDuration,
throttleTimeout: throttleTimeout,
hostPort: hostPort,
devicePort: devicePort,
@@ -225,7 +225,7 @@
///
/// For example, consider a `waitDuration` of `10ms`, and list of event names
/// and arrival times: `a (0ms), b (5ms), c (11ms), d (21ms)`.
-/// The events `a`, `c`, and `d` will be produced as a result.
+/// The events `c` and `d` will be produced as a result.
StreamTransformer<S, S> _throttle<S>({
@required Duration waitDuration,
}) {
@@ -240,13 +240,10 @@
handleData: (S value, EventSink<S> sink) {
latestLine = value;
- final bool isFirstMessage = lastExecution == null;
final int currentTime = DateTime.now().millisecondsSinceEpoch;
lastExecution ??= currentTime;
final int remainingTime = currentTime - lastExecution;
-
- // Always send the first event immediately.
- final int nextExecutionTime = isFirstMessage || remainingTime > waitDuration.inMilliseconds
+ final int nextExecutionTime = remainingTime > waitDuration.inMilliseconds
? 0
: waitDuration.inMilliseconds - remainingTime;
diff --git a/packages/flutter_tools/test/general.shard/ios/ios_deploy_test.dart b/packages/flutter_tools/test/general.shard/ios/ios_deploy_test.dart
index e36d466..121c4f9 100644
--- a/packages/flutter_tools/test/general.shard/ios/ios_deploy_test.dart
+++ b/packages/flutter_tools/test/general.shard/ios/ios_deploy_test.dart
@@ -2,15 +2,10 @@
// Use of this source code is governed by a BSD-style license that can be
// found in the LICENSE file.
-import 'dart:async';
-import 'dart:convert';
-
import 'package:flutter_tools/src/artifacts.dart';
-import 'package:flutter_tools/src/base/file_system.dart';
import 'package:flutter_tools/src/base/logger.dart';
import 'package:flutter_tools/src/base/platform.dart';
import 'package:flutter_tools/src/cache.dart';
-import 'package:flutter_tools/src/ios/devices.dart';
import 'package:flutter_tools/src/ios/ios_deploy.dart';
import 'package:mockito/mockito.dart';
import 'package:process/process.dart';
@@ -26,230 +21,50 @@
expect(environment['PATH'], startsWith('/usr/bin'));
});
- group('IOSDeploy.prepareDebuggerForLaunch', () {
- testWithoutContext('calls ios-deploy with correct arguments and returns when debugger attaches', () async {
- final FakeProcessManager processManager = FakeProcessManager.list(<FakeCommand>[
- FakeCommand(
- command: <String>[
- 'script',
- '-t',
- '0',
- '/dev/null',
- 'ios-deploy',
- '--id',
- '123',
- '--bundle',
- '/',
- '--debug',
- '--args',
- <String>[
- '--enable-dart-profiling',
- ].join(' '),
- ], environment: const <String, String>{
- 'PATH': '/usr/bin:/usr/local/bin:/usr/bin',
- 'DYLD_LIBRARY_PATH': '/path/to/libs',
- },
- stdout: '(lldb) run\nsuccess\nDid finish launching.',
- ),
- ]);
- final IOSDeploy iosDeploy = setUpIOSDeploy(processManager);
- final IOSDeployDebugger iosDeployDebugger = iosDeploy.prepareDebuggerForLaunch(
- deviceId: '123',
- bundlePath: '/',
- launchArguments: <String>['--enable-dart-profiling'],
- interfaceType: IOSDeviceInterface.network,
- );
+ testWithoutContext('IOSDeploy.uninstallApp calls ios-deploy with correct arguments and returns 0 on success', () async {
+ const String deviceId = '123';
+ const String bundleId = 'com.example.app';
+ final FakeProcessManager processManager = FakeProcessManager.list(<FakeCommand>[
+ const FakeCommand(command: <String>[
+ 'ios-deploy',
+ '--id',
+ deviceId,
+ '--uninstall_only',
+ '--bundle_id',
+ bundleId,
+ ])
+ ]);
+ final IOSDeploy iosDeploy = setUpIOSDeploy(processManager);
+ final int exitCode = await iosDeploy.uninstallApp(
+ deviceId: deviceId,
+ bundleId: bundleId,
+ );
- expect(await iosDeployDebugger.launchAndAttach(), isTrue);
- expect(await iosDeployDebugger.logLines.toList(), <String>['Did finish launching.']);
- expect(processManager.hasRemainingExpectations, false);
- });
+ expect(exitCode, 0);
+ expect(processManager.hasRemainingExpectations, false);
});
- group('IOSDeployDebugger', () {
- group('launch', () {
- BufferLogger logger;
+ testWithoutContext('IOSDeploy.uninstallApp returns non-zero exit code when ios-deploy does the same', () async {
+ const String deviceId = '123';
+ const String bundleId = 'com.example.app';
+ final FakeProcessManager processManager = FakeProcessManager.list(<FakeCommand>[
+ const FakeCommand(command: <String>[
+ 'ios-deploy',
+ '--id',
+ deviceId,
+ '--uninstall_only',
+ '--bundle_id',
+ bundleId,
+ ], exitCode: 1)
+ ]);
+ final IOSDeploy iosDeploy = setUpIOSDeploy(processManager);
+ final int exitCode = await iosDeploy.uninstallApp(
+ deviceId: deviceId,
+ bundleId: bundleId,
+ );
- setUp(() {
- logger = BufferLogger.test();
- });
-
- testWithoutContext('debugger attached', () async {
- final FakeProcessManager processManager = FakeProcessManager.list(<FakeCommand>[
- const FakeCommand(
- command: <String>['ios-deploy'],
- stdout: '(lldb) run\r\nsuccess\r\nsuccess\r\nLog on attach1\r\n\r\nLog on attach2\r\n\r\n\r\n\r\nPROCESS_STOPPED\r\nLog after process exit',
- ),
- ]);
- final IOSDeployDebugger iosDeployDebugger = IOSDeployDebugger.test(
- processManager: processManager,
- logger: logger,
- );
- final List<String> receivedLogLines = <String>[];
- final Stream<String> logLines = iosDeployDebugger.logLines
- ..listen(receivedLogLines.add);
-
- expect(await iosDeployDebugger.launchAndAttach(), isTrue);
- await logLines.toList();
- expect(receivedLogLines, <String>[
- 'success', // ignore first "success" from lldb, but log subsequent ones from real logging.
- 'Log on attach1',
- 'Log on attach2',
- '', '']);
- });
-
- testWithoutContext('attach failed', () async {
- final FakeProcessManager processManager = FakeProcessManager.list(<FakeCommand>[
- const FakeCommand(
- command: <String>['ios-deploy'],
- // A success after an error should never happen, but test that we're handling random "successes" anyway.
- stdout: '(lldb) run\r\nerror: process launch failed\r\nsuccess\r\nLog on attach1',
- ),
- ]);
- final IOSDeployDebugger iosDeployDebugger = IOSDeployDebugger.test(
- processManager: processManager,
- logger: logger,
- );
- final List<String> receivedLogLines = <String>[];
- final Stream<String> logLines = iosDeployDebugger.logLines
- ..listen(receivedLogLines.add);
-
- expect(await iosDeployDebugger.launchAndAttach(), isFalse);
- await logLines.toList();
- // Debugger lines are double spaced, separated by an extra \r\n. Skip the extra lines.
- // Still include empty lines other than the extra added newlines.
- expect(receivedLogLines, isEmpty);
- });
-
- testWithoutContext('no provisioning profile 1, stdout', () async {
- final FakeProcessManager processManager = FakeProcessManager.list(<FakeCommand>[
- const FakeCommand(
- command: <String>['ios-deploy'],
- stdout: 'Error 0xe8008015',
- ),
- ]);
- final IOSDeployDebugger iosDeployDebugger = IOSDeployDebugger.test(
- processManager: processManager,
- logger: logger,
- );
-
- await iosDeployDebugger.launchAndAttach();
- expect(logger.errorText, contains('No Provisioning Profile was found'));
- });
-
- testWithoutContext('no provisioning profile 2, stderr', () async {
- final FakeProcessManager processManager = FakeProcessManager.list(<FakeCommand>[
- const FakeCommand(
- command: <String>['ios-deploy'],
- stderr: 'Error 0xe8000067',
- ),
- ]);
- final IOSDeployDebugger iosDeployDebugger = IOSDeployDebugger.test(
- processManager: processManager,
- logger: logger,
- );
- await iosDeployDebugger.launchAndAttach();
- expect(logger.errorText, contains('No Provisioning Profile was found'));
- });
-
- testWithoutContext('device locked', () async {
- final FakeProcessManager processManager = FakeProcessManager.list(<FakeCommand>[
- const FakeCommand(
- command: <String>['ios-deploy'],
- stdout: 'e80000e2',
- ),
- ]);
- final IOSDeployDebugger iosDeployDebugger = IOSDeployDebugger.test(
- processManager: processManager,
- logger: logger,
- );
- await iosDeployDebugger.launchAndAttach();
- expect(logger.errorText, contains('Your device is locked.'));
- });
-
- testWithoutContext('device locked', () async {
- final FakeProcessManager processManager = FakeProcessManager.list(<FakeCommand>[
- const FakeCommand(
- command: <String>['ios-deploy'],
- stdout: 'Error 0xe8000022',
- ),
- ]);
- final IOSDeployDebugger iosDeployDebugger = IOSDeployDebugger.test(
- processManager: processManager,
- logger: logger,
- );
- await iosDeployDebugger.launchAndAttach();
- expect(logger.errorText, contains('Try launching from within Xcode'));
- });
- });
-
- testWithoutContext('detach', () async {
- final StreamController<List<int>> stdin = StreamController<List<int>>();
- final Stream<String> stdinStream = stdin.stream.transform<String>(const Utf8Decoder());
- final FakeProcessManager processManager = FakeProcessManager.list(<FakeCommand>[
- FakeCommand(
- command: const <String>[
- 'ios-deploy',
- ],
- stdout: '(lldb) run\nsuccess',
- stdin: IOSink(stdin.sink),
- ),
- ]);
- final IOSDeployDebugger iosDeployDebugger = IOSDeployDebugger.test(
- processManager: processManager,
- );
- await iosDeployDebugger.launchAndAttach();
- iosDeployDebugger.detach();
- expect(await stdinStream.first, 'process detach');
- });
- });
-
- group('IOSDeploy.uninstallApp', () {
- testWithoutContext('calls ios-deploy with correct arguments and returns 0 on success', () async {
- const String deviceId = '123';
- const String bundleId = 'com.example.app';
- final FakeProcessManager processManager = FakeProcessManager.list(<FakeCommand>[
- const FakeCommand(command: <String>[
- 'ios-deploy',
- '--id',
- deviceId,
- '--uninstall_only',
- '--bundle_id',
- bundleId,
- ])
- ]);
- final IOSDeploy iosDeploy = setUpIOSDeploy(processManager);
- final int exitCode = await iosDeploy.uninstallApp(
- deviceId: deviceId,
- bundleId: bundleId,
- );
-
- expect(exitCode, 0);
- expect(processManager.hasRemainingExpectations, false);
- });
-
- testWithoutContext('returns non-zero exit code when ios-deploy does the same', () async {
- const String deviceId = '123';
- const String bundleId = 'com.example.app';
- final FakeProcessManager processManager = FakeProcessManager.list(<FakeCommand>[
- const FakeCommand(command: <String>[
- 'ios-deploy',
- '--id',
- deviceId,
- '--uninstall_only',
- '--bundle_id',
- bundleId,
- ], exitCode: 1)
- ]);
- final IOSDeploy iosDeploy = setUpIOSDeploy(processManager);
- final int exitCode = await iosDeploy.uninstallApp(
- deviceId: deviceId,
- bundleId: bundleId,
- );
-
- expect(exitCode, 1);
- expect(processManager.hasRemainingExpectations, false);
- });
+ expect(exitCode, 1);
+ expect(processManager.hasRemainingExpectations, false);
});
}
diff --git a/packages/flutter_tools/test/general.shard/ios/ios_device_logger_test.dart b/packages/flutter_tools/test/general.shard/ios/ios_device_logger_test.dart
index 1bdfa8a..bd95e87 100644
--- a/packages/flutter_tools/test/general.shard/ios/ios_device_logger_test.dart
+++ b/packages/flutter_tools/test/general.shard/ios/ios_device_logger_test.dart
@@ -10,7 +10,6 @@
import 'package:flutter_tools/src/convert.dart';
import 'package:flutter_tools/src/device.dart';
import 'package:flutter_tools/src/ios/devices.dart';
-import 'package:flutter_tools/src/ios/ios_deploy.dart';
import 'package:flutter_tools/src/ios/mac.dart';
import 'package:mockito/mockito.dart';
import 'package:vm_service/vm_service.dart';
@@ -31,299 +30,167 @@
artifacts = MockArtifacts();
logger = BufferLogger.test();
when(artifacts.getArtifactPath(Artifact.idevicesyslog, platform: TargetPlatform.ios))
- .thenReturn('idevice-syslog');
+ .thenReturn('idevice-syslog');
});
- group('syslog stream', () {
- testWithoutContext('decodeSyslog decodes a syslog-encoded line', () {
- final String decoded = decodeSyslog(
- r'I \M-b\M^]\M-$\M-o\M-8\M^O syslog \M-B\M-/\'
- r'134_(\M-c\M^C\M^D)_/\M-B\M-/ \M-l\M^F\240!');
+ testWithoutContext('decodeSyslog decodes a syslog-encoded line', () {
+ final String decoded = decodeSyslog(
+ r'I \M-b\M^]\M-$\M-o\M-8\M^O syslog \M-B\M-/\'
+ r'134_(\M-c\M^C\M^D)_/\M-B\M-/ \M-l\M^F\240!');
- expect(decoded, r'I ❤️ syslog ¯\_(ツ)_/¯ 솠!');
- });
+ expect(decoded, r'I ❤️ syslog ¯\_(ツ)_/¯ 솠!');
+ });
- testWithoutContext('decodeSyslog passes through un-decodeable lines as-is', () {
- final String decoded = decodeSyslog(r'I \M-b\M^O syslog!');
+ testWithoutContext('decodeSyslog passes through un-decodeable lines as-is', () {
+ final String decoded = decodeSyslog(r'I \M-b\M^O syslog!');
- expect(decoded, r'I \M-b\M^O syslog!');
- });
+ expect(decoded, r'I \M-b\M^O syslog!');
+ });
- testWithoutContext('IOSDeviceLogReader suppresses non-Flutter lines from output with syslog', () async {
- processManager.addCommand(
- const FakeCommand(
- command: <String>[
- 'idevice-syslog', '-u', '1234',
- ],
- stdout: '''
+ testWithoutContext('IOSDeviceLogReader suppresses non-Flutter lines from output with syslog', () async {
+ processManager.addCommand(
+ const FakeCommand(
+ command: <String>[
+ 'idevice-syslog', '-u', '1234',
+ ],
+ stdout: '''
Runner(Flutter)[297] <Notice>: A is for ari
Runner(libsystem_asl.dylib)[297] <Notice>: libMobileGestalt MobileGestaltSupport.m:153: pid 123 (Runner) does not have sandbox access for frZQaeyWLUvLjeuEK43hmg and IS NOT appropriately entitled
Runner(libsystem_asl.dylib)[297] <Notice>: libMobileGestalt MobileGestalt.c:550: no access to InverseDeviceID (see <rdar://problem/11744455>)
Runner(Flutter)[297] <Notice>: I is for ichigo
Runner(UIKit)[297] <Notice>: E is for enpitsu"
'''
- ),
- );
- final DeviceLogReader logReader = IOSDeviceLogReader.test(
- iMobileDevice: IMobileDevice(
- artifacts: artifacts,
- processManager: processManager,
- cache: fakeCache,
- logger: logger,
- ),
- );
- final List<String> lines = await logReader.logLines.toList();
+ ),
+ );
+ final DeviceLogReader logReader = IOSDeviceLogReader.test(
+ iMobileDevice: IMobileDevice(
+ artifacts: artifacts,
+ processManager: processManager,
+ cache: fakeCache,
+ logger: logger,
+ ),
+ );
+ final List<String> lines = await logReader.logLines.toList();
- expect(lines, <String>['A is for ari', 'I is for ichigo']);
- });
+ expect(lines, <String>['A is for ari', 'I is for ichigo']);
+ });
- testWithoutContext('IOSDeviceLogReader includes multi-line Flutter logs in the output with syslog', () async {
- processManager.addCommand(
- const FakeCommand(
- command: <String>[
- 'idevice-syslog', '-u', '1234',
- ],
- stdout: '''
+ testWithoutContext('IOSDeviceLogReader includes multi-line Flutter logs in the output with syslog', () async {
+ processManager.addCommand(
+ const FakeCommand(
+ command: <String>[
+ 'idevice-syslog', '-u', '1234',
+ ],
+ stdout: '''
Runner(Flutter)[297] <Notice>: This is a multi-line message,
with another Flutter message following it.
Runner(Flutter)[297] <Notice>: This is a multi-line message,
with a non-Flutter log message following it.
Runner(libsystem_asl.dylib)[297] <Notice>: libMobileGestalt
'''
- ),
- );
- final DeviceLogReader logReader = IOSDeviceLogReader.test(
- iMobileDevice: IMobileDevice(
- artifacts: artifacts,
- processManager: processManager,
- cache: fakeCache,
- logger: logger,
- ),
- );
- final List<String> lines = await logReader.logLines.toList();
+ ),
+ );
+ final DeviceLogReader logReader = IOSDeviceLogReader.test(
+ iMobileDevice: IMobileDevice(
+ artifacts: artifacts,
+ processManager: processManager,
+ cache: fakeCache,
+ logger: logger,
+ ),
+ );
+ final List<String> lines = await logReader.logLines.toList();
- expect(lines, <String>[
- 'This is a multi-line message,',
- ' with another Flutter message following it.',
- 'This is a multi-line message,',
- ' with a non-Flutter log message following it.',
- ]);
- });
+ expect(lines, <String>[
+ 'This is a multi-line message,',
+ ' with another Flutter message following it.',
+ 'This is a multi-line message,',
+ ' with a non-Flutter log message following it.',
+ ]);
+ });
- testWithoutContext('includes multi-line Flutter logs in the output', () async {
- processManager.addCommand(
- const FakeCommand(
- command: <String>[
- 'idevice-syslog', '-u', '1234',
- ],
- stdout: '''
+ testWithoutContext('includes multi-line Flutter logs in the output', () async {
+ processManager.addCommand(
+ const FakeCommand(
+ command: <String>[
+ 'idevice-syslog', '-u', '1234',
+ ],
+ stdout: '''
Runner(Flutter)[297] <Notice>: This is a multi-line message,
with another Flutter message following it.
Runner(Flutter)[297] <Notice>: This is a multi-line message,
with a non-Flutter log message following it.
Runner(libsystem_asl.dylib)[297] <Notice>: libMobileGestalt
''',
- ),
- );
+ ),
+ );
- final DeviceLogReader logReader = IOSDeviceLogReader.test(
- iMobileDevice: IMobileDevice(
- artifacts: artifacts,
- processManager: processManager,
- cache: fakeCache,
- logger: logger,
- ),
- );
- final List<String> lines = await logReader.logLines.toList();
+ final DeviceLogReader logReader = IOSDeviceLogReader.test(
+ iMobileDevice: IMobileDevice(
+ artifacts: artifacts,
+ processManager: processManager,
+ cache: fakeCache,
+ logger: logger,
+ ),
+ );
+ final List<String> lines = await logReader.logLines.toList();
- expect(lines, <String>[
- 'This is a multi-line message,',
- ' with another Flutter message following it.',
- 'This is a multi-line message,',
- ' with a non-Flutter log message following it.',
- ]);
- });
+ expect(lines, <String>[
+ 'This is a multi-line message,',
+ ' with another Flutter message following it.',
+ 'This is a multi-line message,',
+ ' with a non-Flutter log message following it.',
+ ]);
});
- group('VM service', () {
- testWithoutContext('IOSDeviceLogReader can listen to VM Service logs', () async {
- final MockVmService vmService = MockVmService();
- final DeviceLogReader logReader = IOSDeviceLogReader.test(
- useSyslog: false,
- iMobileDevice: IMobileDevice(
- artifacts: artifacts,
- processManager: processManager,
- cache: fakeCache,
- logger: logger,
- ),
- );
- final StreamController<Event> stdoutController = StreamController<Event>();
- final StreamController<Event> stderController = StreamController<Event>();
- final Completer<Success> stdoutCompleter = Completer<Success>();
- final Completer<Success> stderrCompleter = Completer<Success>();
- when(vmService.streamListen('Stdout')).thenAnswer((Invocation invocation) {
- return stdoutCompleter.future;
- });
- when(vmService.streamListen('Stderr')).thenAnswer((Invocation invocation) {
- return stderrCompleter.future;
- });
- when(vmService.onStdoutEvent).thenAnswer((Invocation invocation) {
- return stdoutController.stream;
- });
- when(vmService.onStderrEvent).thenAnswer((Invocation invocation) {
- return stderController.stream;
- });
- logReader.connectedVMService = vmService;
-
- stdoutCompleter.complete(Success());
- stderrCompleter.complete(Success());
- stdoutController.add(Event(
- kind: 'Stdout',
- timestamp: 0,
- bytes: base64.encode(utf8.encode(' This is a message ')),
- ));
- stderController.add(Event(
- kind: 'Stderr',
- timestamp: 0,
- bytes: base64.encode(utf8.encode(' And this is an error ')),
- ));
-
- // Wait for stream listeners to fire.
- await expectLater(logReader.logLines, emitsInAnyOrder(<Matcher>[
- equals(' This is a message '),
- equals(' And this is an error '),
- ]));
+ testWithoutContext('IOSDeviceLogReader can listen to VM Service logs', () async {
+ final MockVmService vmService = MockVmService();
+ final DeviceLogReader logReader = IOSDeviceLogReader.test(
+ useSyslog: false,
+ iMobileDevice: IMobileDevice(
+ artifacts: artifacts,
+ processManager: processManager,
+ cache: fakeCache,
+ logger: logger,
+ ),
+ );
+ final StreamController<Event> stdoutController = StreamController<Event>();
+ final StreamController<Event> stderController = StreamController<Event>();
+ final Completer<Success> stdoutCompleter = Completer<Success>();
+ final Completer<Success> stderrCompleter = Completer<Success>();
+ when(vmService.streamListen('Stdout')).thenAnswer((Invocation invocation) {
+ return stdoutCompleter.future;
});
-
- testWithoutContext('IOSDeviceLogReader ignores VM Service logs when attached to debugger', () async {
- final MockVmService vmService = MockVmService();
- final IOSDeviceLogReader logReader = IOSDeviceLogReader.test(
- useSyslog: false,
- iMobileDevice: IMobileDevice(
- artifacts: artifacts,
- processManager: processManager,
- cache: fakeCache,
- logger: logger,
- ),
- );
- final StreamController<Event> stdoutController = StreamController<Event>();
- final StreamController<Event> stderController = StreamController<Event>();
- final Completer<Success> stdoutCompleter = Completer<Success>();
- final Completer<Success> stderrCompleter = Completer<Success>();
- when(vmService.streamListen('Stdout')).thenAnswer((Invocation invocation) {
- return stdoutCompleter.future;
- });
- when(vmService.streamListen('Stderr')).thenAnswer((Invocation invocation) {
- return stderrCompleter.future;
- });
- when(vmService.onStdoutEvent).thenAnswer((Invocation invocation) {
- return stdoutController.stream;
- });
- when(vmService.onStderrEvent).thenAnswer((Invocation invocation) {
- return stderController.stream;
- });
- logReader.connectedVMService = vmService;
-
- stdoutCompleter.complete(Success());
- stderrCompleter.complete(Success());
- stdoutController.add(Event(
- kind: 'Stdout',
- timestamp: 0,
- bytes: base64.encode(utf8.encode(' This is a message ')),
- ));
- stderController.add(Event(
- kind: 'Stderr',
- timestamp: 0,
- bytes: base64.encode(utf8.encode(' And this is an error ')),
- ));
-
- final MockIOSDeployDebugger iosDeployDebugger = MockIOSDeployDebugger();
- when(iosDeployDebugger.debuggerAttached).thenReturn(true);
-
- final Stream<String> debuggingLogs = Stream<String>.fromIterable(<String>[
- 'Message from debugger'
- ]);
- when(iosDeployDebugger.logLines).thenAnswer((Invocation invocation) => debuggingLogs);
- logReader.debuggerStream = iosDeployDebugger;
-
- // Wait for stream listeners to fire.
- await expectLater(logReader.logLines, emitsInAnyOrder(<Matcher>[
- equals('Message from debugger'),
- ]));
+ when(vmService.streamListen('Stderr')).thenAnswer((Invocation invocation) {
+ return stderrCompleter.future;
});
- });
-
- group('debugger stream', () {
- testWithoutContext('IOSDeviceLogReader removes metadata prefix from lldb output', () async {
- final Stream<String> debuggingLogs = Stream<String>.fromIterable(<String>[
- '2020-09-15 19:15:10.931434-0700 Runner[541:226276] Did finish launching.',
- '2020-09-15 19:15:10.931434-0700 Runner[541:226276] [Category] Did finish launching from logging category.',
- 'stderr from dart',
- '',
- ]);
-
- final IOSDeviceLogReader logReader = IOSDeviceLogReader.test(
- iMobileDevice: IMobileDevice(
- artifacts: artifacts,
- processManager: processManager,
- cache: fakeCache,
- logger: logger,
- ),
- useSyslog: false,
- );
- final MockIOSDeployDebugger iosDeployDebugger = MockIOSDeployDebugger();
- when(iosDeployDebugger.logLines).thenAnswer((Invocation invocation) => debuggingLogs);
- logReader.debuggerStream = iosDeployDebugger;
- final Future<List<String>> logLines = logReader.logLines.toList();
-
- expect(await logLines, <String>[
- 'Did finish launching.',
- '[Category] Did finish launching from logging category.',
- 'stderr from dart',
- '',
- ]);
+ when(vmService.onStdoutEvent).thenAnswer((Invocation invocation) {
+ return stdoutController.stream;
});
-
- testWithoutContext('errors on debugger stream closes log stream', () async {
- final Stream<String> debuggingLogs = Stream<String>.error('ios-deploy error');
- final IOSDeviceLogReader logReader = IOSDeviceLogReader.test(
- iMobileDevice: IMobileDevice(
- artifacts: artifacts,
- processManager: processManager,
- cache: fakeCache,
- logger: logger,
- ),
- useSyslog: false,
- );
- final Completer<void> streamComplete = Completer<void>();
- final MockIOSDeployDebugger iosDeployDebugger = MockIOSDeployDebugger();
- when(iosDeployDebugger.logLines).thenAnswer((Invocation invocation) => debuggingLogs);
- logReader.logLines.listen(null, onError: (Object error) => streamComplete.complete());
- logReader.debuggerStream = iosDeployDebugger;
-
- await streamComplete.future;
+ when(vmService.onStderrEvent).thenAnswer((Invocation invocation) {
+ return stderController.stream;
});
+ logReader.connectedVMService = vmService;
- testWithoutContext('detaches debugger', () async {
- final IOSDeviceLogReader logReader = IOSDeviceLogReader.test(
- iMobileDevice: IMobileDevice(
- artifacts: artifacts,
- processManager: processManager,
- cache: fakeCache,
- logger: logger,
- ),
- useSyslog: false,
- );
- final MockIOSDeployDebugger iosDeployDebugger = MockIOSDeployDebugger();
- when(iosDeployDebugger.logLines).thenAnswer((Invocation invocation) => const Stream<String>.empty());
- logReader.debuggerStream = iosDeployDebugger;
+ stdoutCompleter.complete(Success());
+ stderrCompleter.complete(Success());
+ stdoutController.add(Event(
+ kind: 'Stdout',
+ timestamp: 0,
+ bytes: base64.encode(utf8.encode(' This is a message ')),
+ ));
+ stderController.add(Event(
+ kind: 'Stderr',
+ timestamp: 0,
+ bytes: base64.encode(utf8.encode(' And this is an error ')),
+ ));
- logReader.dispose();
- verify(iosDeployDebugger.detach());
- });
+ // Wait for stream listeners to fire.
+ await expectLater(logReader.logLines, emitsInAnyOrder(<Matcher>[
+ equals(' This is a message '),
+ equals(' And this is an error '),
+ ]));
});
}
class MockArtifacts extends Mock implements Artifacts {}
class MockVmService extends Mock implements VmService {}
-class MockIOSDeployDebugger extends Mock implements IOSDeployDebugger {}
diff --git a/packages/flutter_tools/test/general.shard/ios/ios_device_start_prebuilt_test.dart b/packages/flutter_tools/test/general.shard/ios/ios_device_start_prebuilt_test.dart
index 806f7ff..12c8777 100644
--- a/packages/flutter_tools/test/general.shard/ios/ios_device_start_prebuilt_test.dart
+++ b/packages/flutter_tools/test/general.shard/ios/ios_device_start_prebuilt_test.dart
@@ -67,25 +67,19 @@
// The command used to actually launch the app with args in debug.
const FakeCommand kLaunchDebugCommand = FakeCommand(command: <String>[
- 'script',
- '-t',
- '0',
- '/dev/null',
'ios-deploy',
'--id',
'123',
'--bundle',
'/',
- '--debug',
'--no-wifi',
+ '--justlaunch',
'--args',
'--enable-dart-profiling --enable-service-port-fallback --disable-service-auth-codes --observatory-port=60700 --enable-checked-mode --verify-entry-points'
], environment: <String, String>{
'PATH': '/usr/bin:null',
'DYLD_LIBRARY_PATH': '/path/to/libraries',
-},
-stdout: '(lldb) run\nsuccess',
-);
+});
void main() {
// TODO(jonahwilliams): This test doesn't really belong here but
@@ -108,7 +102,7 @@
});
// Still uses context for analytics and mDNS.
- testUsingContext('IOSDevice.startApp succeeds in debug mode via mDNS discovery when log reading fails', () async {
+ testUsingContext('IOSDevice.startApp succeeds in debug mode via mDNS discovery', () async {
final FileSystem fileSystem = MemoryFileSystem.test();
final FakeProcessManager processManager = FakeProcessManager.list(<FakeCommand>[
kDeployCommand,
@@ -151,7 +145,6 @@
debuggingOptions: DebuggingOptions.enabled(BuildInfo.debug),
platformArgs: <String, dynamic>{},
fallbackPollingDelay: Duration.zero,
- fallbackThrottleTimeout: const Duration(milliseconds: 10),
);
verify(globals.flutterUsage.sendEvent('ios-handshake', 'mdns-success')).called(1);
@@ -164,58 +157,7 @@
});
// Still uses context for analytics and mDNS.
- testUsingContext('IOSDevice.startApp succeeds in debug mode via log reading', () async {
- final FileSystem fileSystem = MemoryFileSystem.test();
- final FakeProcessManager processManager = FakeProcessManager.list(<FakeCommand>[
- kDeployCommand,
- kLaunchDebugCommand,
- ]);
- final IOSDevice device = setUpIOSDevice(
- processManager: processManager,
- fileSystem: fileSystem,
- vmServiceConnector: (String string, {Log log}) async {
- throw const io.SocketException(
- 'OS Error: Connection refused, errno = 61, address = localhost, port '
- '= 58943',
- );
- },
- );
- final IOSApp iosApp = PrebuiltIOSApp(
- projectBundleId: 'app',
- bundleName: 'Runner',
- bundleDir: fileSystem.currentDirectory,
- );
- final FakeDeviceLogReader deviceLogReader = FakeDeviceLogReader();
-
- device.portForwarder = const NoOpDevicePortForwarder();
- device.setLogReader(iosApp, deviceLogReader);
-
- // Start writing messages to the log reader.
- Timer.run(() {
- deviceLogReader.addLine('Foo');
- deviceLogReader.addLine('Observatory listening on http://127.0.0.1:456');
- });
-
- final LaunchResult launchResult = await device.startApp(iosApp,
- prebuiltApplication: true,
- debuggingOptions: DebuggingOptions.enabled(BuildInfo.debug),
- platformArgs: <String, dynamic>{},
- fallbackPollingDelay: Duration.zero,
- fallbackThrottleTimeout: const Duration(milliseconds: 10),
- );
-
- expect(launchResult.started, true);
- expect(launchResult.hasObservatory, true);
- verify(globals.flutterUsage.sendEvent('ios-handshake', 'log-success')).called(1);
- verifyNever(globals.flutterUsage.sendEvent('ios-handshake', 'mdns-failure'));
- expect(await device.stopApp(iosApp), false);
- }, overrides: <Type, Generator>{
- MDnsObservatoryDiscovery: () => MockMDnsObservatoryDiscovery(),
- Usage: () => MockUsage(),
- });
-
- // Still uses context for analytics and mDNS.
- testUsingContext('IOSDevice.startApp fails in debug mode when Observatory URI is malformed', () async {
+ testUsingContext('IOSDevice.startApp succeeds in debug mode when mDNS fails', () async {
final FileSystem fileSystem = MemoryFileSystem.test();
final FakeProcessManager processManager = FakeProcessManager.list(<FakeCommand>[
kDeployCommand,
@@ -244,15 +186,69 @@
// Now that the reader is used, start writing messages to it.
Timer.run(() {
deviceLogReader.addLine('Foo');
- deviceLogReader.addLine('Observatory listening on http://127.0.0.1:456abc');
+ deviceLogReader.addLine('Observatory listening on http://127.0.0.1:456');
});
+ when(MDnsObservatoryDiscovery.instance.getObservatoryUri(any, any, usesIpv6: anyNamed('usesIpv6')))
+ .thenAnswer((Invocation invocation) async => null);
final LaunchResult launchResult = await device.startApp(iosApp,
prebuiltApplication: true,
debuggingOptions: DebuggingOptions.enabled(BuildInfo.debug),
platformArgs: <String, dynamic>{},
fallbackPollingDelay: Duration.zero,
- // fallbackThrottleTimeout: const Duration(milliseconds: 10),
+ );
+
+ expect(launchResult.started, true);
+ expect(launchResult.hasObservatory, true);
+ verify(globals.flutterUsage.sendEvent('ios-handshake', 'mdns-failure')).called(1);
+ verify(globals.flutterUsage.sendEvent('ios-handshake', 'fallback-success')).called(1);
+ expect(await device.stopApp(iosApp), false);
+ }, overrides: <Type, Generator>{
+ Usage: () => MockUsage(),
+ MDnsObservatoryDiscovery: () => MockMDnsObservatoryDiscovery(),
+ });
+
+ // Still uses context for analytics and mDNS.
+ testUsingContext('IOSDevice.startApp fails in debug mode when mDNS fails and '
+ 'when Observatory URI is malformed', () async {
+ final FileSystem fileSystem = MemoryFileSystem.test();
+ final FakeProcessManager processManager = FakeProcessManager.list(<FakeCommand>[
+ kDeployCommand,
+ kLaunchDebugCommand,
+ ]);
+ final IOSDevice device = setUpIOSDevice(
+ processManager: processManager,
+ fileSystem: fileSystem,
+ vmServiceConnector: (String string, {Log log}) async {
+ throw const io.SocketException(
+ 'OS Error: Connection refused, errno = 61, address = localhost, port '
+ '= 58943',
+ );
+ },
+ );
+ final IOSApp iosApp = PrebuiltIOSApp(
+ projectBundleId: 'app',
+ bundleName: 'Runner',
+ bundleDir: fileSystem.currentDirectory,
+ );
+ final FakeDeviceLogReader deviceLogReader = FakeDeviceLogReader();
+
+ device.portForwarder = const NoOpDevicePortForwarder();
+ device.setLogReader(iosApp, deviceLogReader);
+
+ // Now that the reader is used, start writing messages to it.
+ Timer.run(() {
+ deviceLogReader.addLine('Foo');
+ deviceLogReader.addLine('Observatory listening on http:/:/127.0.0.1:456');
+ });
+ when(MDnsObservatoryDiscovery.instance.getObservatoryUri(any, any, usesIpv6: anyNamed('usesIpv6')))
+ .thenAnswer((Invocation invocation) async => null);
+
+ final LaunchResult launchResult = await device.startApp(iosApp,
+ prebuiltApplication: true,
+ debuggingOptions: DebuggingOptions.enabled(BuildInfo.debug),
+ platformArgs: <String, dynamic>{},
+ fallbackPollingDelay: Duration.zero,
);
expect(launchResult.started, false);
@@ -263,8 +259,8 @@
label: anyNamed('label'),
value: anyNamed('value'),
)).called(1);
- verify(globals.flutterUsage.sendEvent('ios-handshake', 'log-failure')).called(1);
verify(globals.flutterUsage.sendEvent('ios-handshake', 'mdns-failure')).called(1);
+ verify(globals.flutterUsage.sendEvent('ios-handshake', 'fallback-failure')).called(1);
}, overrides: <Type, Generator>{
MDnsObservatoryDiscovery: () => MockMDnsObservatoryDiscovery(),
Usage: () => MockUsage(),
@@ -392,7 +388,6 @@
debuggingOptions: DebuggingOptions.disabled(BuildInfo.release),
platformArgs: <String, dynamic>{},
fallbackPollingDelay: Duration.zero,
- fallbackThrottleTimeout: const Duration(milliseconds: 10),
);
expect(launchResult.started, true);
@@ -410,17 +405,13 @@
kDeployCommand,
FakeCommand(
command: <String>[
- 'script',
- '-t',
- '0',
- '/dev/null',
'ios-deploy',
'--id',
'123',
'--bundle',
'/',
- '--debug',
'--no-wifi',
+ '--justlaunch',
// The arguments below are determined by what is passed into
// the debugging options argument to startApp.
'--args',
@@ -445,8 +436,7 @@
], environment: const <String, String>{
'PATH': '/usr/bin:null',
'DYLD_LIBRARY_PATH': '/path/to/libraries',
- },
- stdout: '(lldb) run\nsuccess',
+ }
)
]);
final IOSDevice device = setUpIOSDevice(
@@ -465,15 +455,22 @@
bundleName: 'Runner',
bundleDir: fileSystem.currentDirectory,
);
- final FakeDeviceLogReader deviceLogReader = FakeDeviceLogReader();
+ final Uri uri = Uri(
+ scheme: 'http',
+ host: '127.0.0.1',
+ port: 1234,
+ path: 'observatory',
+ );
+ device.setLogReader(iosApp, FakeDeviceLogReader());
device.portForwarder = const NoOpDevicePortForwarder();
- device.setLogReader(iosApp, deviceLogReader);
- // Start writing messages to the log reader.
- Timer.run(() {
- deviceLogReader.addLine('Observatory listening on http://127.0.0.1:1234');
- });
+ when(MDnsObservatoryDiscovery.instance.getObservatoryUri(
+ any,
+ any,
+ usesIpv6: anyNamed('usesIpv6'),
+ hostVmservicePort: anyNamed('hostVmservicePort')
+ )).thenAnswer((Invocation invocation) async => uri);
final LaunchResult launchResult = await device.startApp(iosApp,
prebuiltApplication: true,
@@ -495,7 +492,6 @@
),
platformArgs: <String, dynamic>{},
fallbackPollingDelay: Duration.zero,
- fallbackThrottleTimeout: const Duration(milliseconds: 10),
);
expect(launchResult.started, true);