Resume isolate before terminating tests to prevent flutter_tester leaks in integration tests (#45248)
* Resume isolate before terminating tests to prevent flutter_tester leak
* Fix lint
* Catch exceptions from resume() as well as timeout()
* Formatting fixes
* Don't try to resume if there's no vm service
* Fix handling of timeouts to not leak futures
diff --git a/packages/flutter_tools/test/integration.shard/test_driver.dart b/packages/flutter_tools/test/integration.shard/test_driver.dart
index 314a479..4fb07e3 100644
--- a/packages/flutter_tools/test/integration.shard/test_driver.dart
+++ b/packages/flutter_tools/test/integration.shard/test_driver.dart
@@ -164,6 +164,12 @@
if (_processPid == null) {
return -1;
}
+ // If we try to kill the process while it's paused, we'll end up terminating
+ // it forcefully and it won't terminate child processes, so we need to ensure
+ // it's running before terminating.
+ await resume().timeout(defaultTimeout)
+ .catchError((Object e) => _debugPrint('Ignoring failure to resume during shutdown'));
+
_debugPrint('Sending SIGTERM to $_processPid..');
ProcessSignal.SIGTERM.send(_processPid);
return _process.exitCode.timeout(quitTimeout, onTimeout: _killForcefully);
@@ -345,7 +351,7 @@
return;
}
if ((event != null && json['event'] == event) ||
- (id != null && json['id'] == id)) {
+ (id != null && json['id'] == id)) {
await subscription.cancel();
_debugPrint('OK ($interestingOccurrence)');
response.complete(json);
@@ -380,10 +386,8 @@
if (_printDebugOutputToStdOut) {
_debugPrint('$task...');
- return callback()..timeout(timeout, onTimeout: () {
- _debugPrint('$task is taking longer than usual...');
- return null;
- });
+ final Timer longWarning = Timer(timeout, () => _debugPrint('$task is taking longer than usual...'));
+ return callback().whenComplete(longWarning.cancel);
}
// We're not showing all output to the screen, so let's capture the output
@@ -399,14 +403,12 @@
}
final StreamSubscription<String> subscription = _allMessages.stream.listen(logMessage);
- final Future<T> future = callback();
-
- future.timeout(timeout ?? defaultTimeout, onTimeout: () {
+ final Timer longWarning = Timer(timeout, () {
_debugPrint(messages.toString());
timeoutExpired = true;
_debugPrint('$task is taking longer than usual...');
- return null;
});
+ final Future<T> future = callback().whenComplete(longWarning.cancel);
return future.catchError((dynamic error) {
if (!timeoutExpired) {
@@ -525,7 +527,7 @@
// have already completed.
_currentRunningAppId = (await started)['params']['appId'] as String;
prematureExitGuard.complete();
- } catch(error, stackTrace) {
+ } catch (error, stackTrace) {
prematureExitGuard.completeError(error, stackTrace);
}
}());
@@ -546,7 +548,7 @@
'app.restart',
<String, dynamic>{'appId': _currentRunningAppId, 'fullRestart': fullRestart, 'pause': pause},
);
- _debugPrint('${ fullRestart ? "Hot restart" : "Hot reload" } complete.');
+ _debugPrint('${fullRestart ? "Hot restart" : "Hot reload"} complete.');
if (hotReloadResponse == null || hotReloadResponse['code'] != 0) {
_throwErrorResponse('Hot ${fullRestart ? 'restart' : 'reload'} request failed');