Unverified Commit 6683468f authored by Victoria Ashworth's avatar Victoria Ashworth Committed by GitHub

Add debugging for iOS startup test flakes (#130099)

Adding debugging for https://github.com/flutter/flutter/issues/129836.

Takes a screenshot when startup test takes too long (10 minutes).

Also, removes some old debugging and add new debugging message.
parent d55a7d89
......@@ -771,6 +771,15 @@ class StartupTest {
const int maxFailures = 3;
int currentFailures = 0;
for (int i = 0; i < iterations; i += 1) {
// Startup should not take more than a few minutes. After 10 minutes,
// take a screenshot to help debug.
final Timer timer = Timer(const Duration(minutes: 10), () async {
print('Startup not completed within 10 minutes. Taking a screenshot...');
await _flutterScreenshot(
device.deviceId,
'screenshot_startup_${DateTime.now().toLocal().toIso8601String()}.png',
);
});
final int result = await flutter('run', options: <String>[
'--no-android-gradle-daemon',
'--no-publish-port',
......@@ -782,7 +791,8 @@ class StartupTest {
device.deviceId,
if (applicationBinaryPath != null)
'--use-application-binary=$applicationBinaryPath',
], canFail: true);
], canFail: true);
timer.cancel();
if (result == 0) {
final Map<String, dynamic> data = json.decode(
file('${_testOutputDirectory(testDirectory)}/start_up_info.json').readAsStringSync(),
......@@ -790,20 +800,10 @@ class StartupTest {
results.add(data);
} else {
currentFailures += 1;
if (hostAgent.dumpDirectory != null) {
await flutter(
'screenshot',
options: <String>[
'-d',
device.deviceId,
'--out',
hostAgent.dumpDirectory!
.childFile('screenshot_startup_failure_$currentFailures.png')
.path,
],
canFail: true,
);
}
await _flutterScreenshot(
device.deviceId,
'screenshot_startup_failure_$currentFailures.png',
);
i -= 1;
if (currentFailures == maxFailures) {
return TaskResult.failure('Application failed to start $maxFailures times');
......@@ -829,6 +829,23 @@ class StartupTest {
]);
});
}
Future<void> _flutterScreenshot(String deviceId, String screenshotName) async {
if (hostAgent.dumpDirectory != null) {
await flutter(
'screenshot',
options: <String>[
'-d',
deviceId,
'--out',
hostAgent.dumpDirectory!
.childFile(screenshotName)
.path,
],
canFail: true,
);
}
}
}
/// A one-off test to verify that devtools starts in profile mode.
......
......@@ -338,6 +338,8 @@ class IOSDeployDebugger {
RegExp lldbRun = RegExp(r'\(lldb\)\s*run');
final Completer<bool> debuggerCompleter = Completer<bool>();
bool receivedLogs = false;
try {
_iosDeployProcess = await _processUtils.start(
_launchCommand,
......@@ -386,8 +388,6 @@ class IOSDeployDebugger {
if (lldbRun.hasMatch(line)) {
_logger.printTrace(line);
_debuggerState = _IOSDeployDebuggerState.launching;
// TODO(vashworth): Remove all debugger state comments when https://github.com/flutter/flutter/issues/126412 is resolved.
_logger.printTrace('Debugger state set to launching.');
return;
}
// Next line after "run" must be "success", or the attach failed.
......@@ -396,7 +396,6 @@ class IOSDeployDebugger {
_logger.printTrace(line);
final bool attachSuccess = line == 'success';
_debuggerState = attachSuccess ? _IOSDeployDebuggerState.attached : _IOSDeployDebuggerState.detached;
_logger.printTrace('Debugger state set to ${attachSuccess ? 'attached' : 'detached'}.');
if (!debuggerCompleter.isCompleted) {
debuggerCompleter.complete(attachSuccess);
}
......@@ -425,7 +424,6 @@ class IOSDeployDebugger {
// Even though we're not "detached", just stopped, mark as detached so the backtrace
// is only show in verbose.
_debuggerState = _IOSDeployDebuggerState.detached;
_logger.printTrace('Debugger state set to detached.');
// If we paused the app and are waiting to resume it, complete the completer
final Completer<void>? processResumeCompleter = _processResumeCompleter;
......@@ -465,7 +463,6 @@ class IOSDeployDebugger {
_logger.printTrace(line);
// we marked this detached when we received [_backTraceAll]
_debuggerState = _IOSDeployDebuggerState.attached;
_logger.printTrace('Debugger state set to attached.');
return;
}
......@@ -480,6 +477,16 @@ class IOSDeployDebugger {
// This will still cause "legit" logged newlines to be doubled...
} else if (!_debuggerOutput.isClosed) {
_debuggerOutput.add(line);
// Sometimes the `ios-deploy` process does not return logs from the
// application after attaching, such as the Dart VM url. In CI,
// `idevicesyslog` is used as a fallback to get logs. Print a
// message to indicate whether logs were received from `ios-deploy`
// to help with debugging.
if (!receivedLogs) {
_logger.printTrace('Received logs from ios-deploy.');
receivedLogs = true;
}
}
lastLineFromDebugger = line;
});
......
......@@ -341,6 +341,33 @@ void main () {
await iosDeployDebugger.launchAndAttach();
expect(logger.errorText, contains('Try launching from within Xcode'));
});
testWithoutContext('debugger attached and received logs', () async {
final StreamController<List<int>> stdin = StreamController<List<int>>();
final FakeProcessManager processManager = FakeProcessManager.list(<FakeCommand>[
FakeCommand(
command: const <String>['ios-deploy'],
stdout: '(lldb) run\r\nsuccess\r\nLog on attach1\r\n\r\nLog on attach2\r\n',
stdin: IOSink(stdin.sink),
),
]);
final IOSDeployDebugger iosDeployDebugger = IOSDeployDebugger.test(
processManager: processManager,
logger: logger,
);
final List<String> receivedLogLines = <String>[];
final Stream<String> logLines = iosDeployDebugger.logLines
..listen(receivedLogLines.add);
expect(iosDeployDebugger.logLines, emitsInOrder(<String>[
'Log on attach1',
'Log on attach2',
]));
expect(await iosDeployDebugger.launchAndAttach(), isTrue);
await logLines.drain();
expect(LineSplitter.split(logger.traceText), containsOnce('Received logs from ios-deploy.'));
});
});
testWithoutContext('detach', () async {
......
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