Unverified Commit 283ec9e2 authored by Yegor's avatar Yegor Committed by GitHub

Do not wait for connections after process has exited (#54497)

parent d119e5f1
...@@ -40,12 +40,20 @@ Future<Map<String, dynamic>> runTask( ...@@ -40,12 +40,20 @@ Future<Map<String, dynamic>> runTask(
bool runnerFinished = false; bool runnerFinished = false;
final Completer<Uri> uri = Completer<Uri>();
runner.exitCode.whenComplete(() { runner.exitCode.whenComplete(() {
if (!uri.isCompleted) {
// The runner process exited prematurely.
uri.completeError(Exception(
'The task runner process exited before opening a VM service connection. '
'A common cause for this is when a task script does not actually create '
'a task.',
));
}
runnerFinished = true; runnerFinished = true;
}); });
final Completer<Uri> uri = Completer<Uri>();
final StreamSubscription<String> stdoutSub = runner.stdout final StreamSubscription<String> stdoutSub = runner.stdout
.transform<String>(const Utf8Decoder()) .transform<String>(const Utf8Decoder())
.transform<String>(const LineSplitter()) .transform<String>(const LineSplitter())
...@@ -68,7 +76,7 @@ Future<Map<String, dynamic>> runTask( ...@@ -68,7 +76,7 @@ Future<Map<String, dynamic>> runTask(
}); });
try { try {
final VMIsolateRef isolate = await _connectToRunnerIsolate(await uri.future); final VMIsolateRef isolate = await _connectToRunnerIsolate(await uri.future, () => !runnerFinished);
final Map<String, dynamic> taskResult = await isolate.invokeExtension('ext.cocoonRunTask') as Map<String, dynamic>; final Map<String, dynamic> taskResult = await isolate.invokeExtension('ext.cocoonRunTask') as Map<String, dynamic>;
await runner.exitCode; await runner.exitCode;
return taskResult; return taskResult;
...@@ -81,7 +89,7 @@ Future<Map<String, dynamic>> runTask( ...@@ -81,7 +89,7 @@ Future<Map<String, dynamic>> runTask(
} }
} }
Future<VMIsolateRef> _connectToRunnerIsolate(Uri vmServiceUri) async { Future<VMIsolateRef> _connectToRunnerIsolate(Uri vmServiceUri, bool Function() keepTrying) async {
final List<String> pathSegments = <String>[ final List<String> pathSegments = <String>[
// Add authentication code. // Add authentication code.
if (vmServiceUri.pathSegments.isNotEmpty) vmServiceUri.pathSegments[0], if (vmServiceUri.pathSegments.isNotEmpty) vmServiceUri.pathSegments[0],
...@@ -91,7 +99,7 @@ Future<VMIsolateRef> _connectToRunnerIsolate(Uri vmServiceUri) async { ...@@ -91,7 +99,7 @@ Future<VMIsolateRef> _connectToRunnerIsolate(Uri vmServiceUri) async {
pathSegments).toString(); pathSegments).toString();
final Stopwatch stopwatch = Stopwatch()..start(); final Stopwatch stopwatch = Stopwatch()..start();
while (true) { while (keepTrying()) {
try { try {
// Make sure VM server is up by successfully opening and closing a socket. // Make sure VM server is up by successfully opening and closing a socket.
await (await WebSocket.connect(url)).close(); await (await WebSocket.connect(url)).close();
...@@ -110,6 +118,8 @@ Future<VMIsolateRef> _connectToRunnerIsolate(Uri vmServiceUri) async { ...@@ -110,6 +118,8 @@ Future<VMIsolateRef> _connectToRunnerIsolate(Uri vmServiceUri) async {
await Future<void>.delayed(const Duration(milliseconds: 50)); await Future<void>.delayed(const Duration(milliseconds: 50));
} }
} }
throw Exception('Failed to connect to Dart VM service.');
} }
Future<void> cleanupSystem() async { Future<void> cleanupSystem() async {
......
...@@ -24,43 +24,43 @@ void main() { ...@@ -24,43 +24,43 @@ void main() {
return scriptProcess; return scriptProcess;
} }
Future<void> expectScriptResult(List<String> testNames, int expectedExitCode) async { Future<void> expectScriptResult(List<String> testNames, { bool expectSuccess }) async {
final ProcessResult result = await runScript(testNames); final ProcessResult result = await runScript(testNames);
expect(result.exitCode, expectedExitCode, expect(result.exitCode, expectSuccess ? 0 : isNot(equals(0)),
reason: '[ stderr from test process ]\n\n${result.stderr}\n\n[ end of stderr ]' reason: '[ stderr from test process ]\n\n${result.stderr}\n\n[ end of stderr ]'
'\n\n[ stdout from test process ]\n\n${result.stdout}\n\n[ end of stdout ]'); '\n\n[ stdout from test process ]\n\n${result.stdout}\n\n[ end of stdout ]');
} }
test('exits with code 0 when succeeds', () async { test('exits with code 0 when succeeds', () async {
await expectScriptResult(<String>['smoke_test_success'], 0); await expectScriptResult(<String>['smoke_test_success'], expectSuccess: true);
}); });
test('accepts file paths', () async { test('accepts file paths', () async {
await expectScriptResult(<String>['bin/tasks/smoke_test_success.dart'], 0); await expectScriptResult(<String>['bin/tasks/smoke_test_success.dart'], expectSuccess: true);
}); });
test('rejects invalid file paths', () async { test('rejects invalid file paths', () async {
await expectScriptResult(<String>['lib/framework/adb.dart'], 1); await expectScriptResult(<String>['lib/framework/adb.dart'], expectSuccess: false);
}); });
test('exits with code 1 when task throws', () async { test('exits with code 1 when task throws', () async {
await expectScriptResult(<String>['smoke_test_throws'], 1); await expectScriptResult(<String>['smoke_test_throws'], expectSuccess: false);
}); });
test('exits with code 1 when fails', () async { test('exits with code 1 when fails', () async {
await expectScriptResult(<String>['smoke_test_failure'], 1); await expectScriptResult(<String>['smoke_test_failure'], expectSuccess: false);
}); });
test('exits with code 1 when fails to connect', () async { test('exits with code 1 when fails to connect', () async {
await expectScriptResult(<String>['smoke_test_setup_failure'], 1); await expectScriptResult(<String>['smoke_test_setup_failure'], expectSuccess: false);
}, skip: true); // https://github.com/flutter/flutter/issues/53707 });
test('exits with code 1 when results are mixed', () async { test('exits with code 1 when results are mixed', () async {
await expectScriptResult(<String>[ await expectScriptResult(<String>[
'smoke_test_failure', 'smoke_test_failure',
'smoke_test_success', 'smoke_test_success',
], ],
1, expectSuccess: false,
); );
}); });
}); });
......
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