Skip to content

Commit b8f5394

Browse files
[flutter_tools] Fix Future error handling ArgumentError in doctor --android-licenses (#119977)
* wip * write test * make error handling printError * remove diff
1 parent 2e39bad commit b8f5394

File tree

2 files changed

+53
-7
lines changed

2 files changed

+53
-7
lines changed

packages/flutter_tools/lib/src/android/android_workflow.dart

+10-7
Original file line numberDiff line numberDiff line change
@@ -436,11 +436,14 @@ class AndroidLicenseValidator extends DoctorValidator {
436436
unawaited(process.stdin.addStream(_stdio.stdin)
437437
// If the process exits unexpectedly with an error, that will be
438438
// handled by the caller.
439-
.catchError((dynamic err, StackTrace stack) {
440-
_logger.printTrace('Echoing stdin to the licenses subprocess failed:');
441-
_logger.printTrace('$err\n$stack');
442-
}
443-
));
439+
.then(
440+
(Object? socket) => socket,
441+
onError: (dynamic err, StackTrace stack) {
442+
_logger.printError('Echoing stdin to the licenses subprocess failed:');
443+
_logger.printError('$err\n$stack');
444+
},
445+
),
446+
);
444447

445448
// Wait for stdout and stderr to be fully processed, because process.exitCode
446449
// may complete first.
@@ -450,8 +453,8 @@ class AndroidLicenseValidator extends DoctorValidator {
450453
_stdio.addStderrStream(process.stderr),
451454
]);
452455
} on Exception catch (err, stack) {
453-
_logger.printTrace('Echoing stdout or stderr from the license subprocess failed:');
454-
_logger.printTrace('$err\n$stack');
456+
_logger.printError('Echoing stdout or stderr from the license subprocess failed:');
457+
_logger.printError('$err\n$stack');
455458
}
456459

457460
final int exitCode = await process.exitCode;

packages/flutter_tools/test/general.shard/android/android_workflow_test.dart

+43
Original file line numberDiff line numberDiff line change
@@ -7,6 +7,7 @@ import 'package:flutter_tools/src/android/android_sdk.dart';
77
import 'package:flutter_tools/src/android/android_studio.dart';
88
import 'package:flutter_tools/src/android/android_workflow.dart';
99
import 'package:flutter_tools/src/base/file_system.dart';
10+
import 'package:flutter_tools/src/base/io.dart';
1011
import 'package:flutter_tools/src/base/logger.dart';
1112
import 'package:flutter_tools/src/base/platform.dart';
1213
import 'package:flutter_tools/src/base/user_messages.dart';
@@ -311,6 +312,37 @@ Review licenses that have not been accepted (y/N)?
311312
expect(licenseValidator.runLicenseManager(), throwsToolExit());
312313
});
313314

315+
testWithoutContext('runLicenseManager handles broken pipe without ArgumentError', () async {
316+
sdk.sdkManagerPath = '/foo/bar/sdkmanager';
317+
const String exceptionMessage = 'Write failed (OS Error: Broken pipe, errno = 32), port = 0';
318+
const SocketException exception = SocketException(exceptionMessage);
319+
// By using a `Socket` generic parameter, the stdin.addStream will return a `Future<Socket>`
320+
// We are testing that our error handling properly handles futures of this type
321+
final ThrowingStdin<Socket> fakeStdin = ThrowingStdin<Socket>(exception);
322+
final FakeCommand licenseCommand = FakeCommand(
323+
command: <String>[sdk.sdkManagerPath!, '--licenses'],
324+
stdin: fakeStdin,
325+
);
326+
processManager.addCommand(licenseCommand);
327+
final BufferLogger logger = BufferLogger.test();
328+
329+
final AndroidLicenseValidator licenseValidator = AndroidLicenseValidator(
330+
androidSdk: sdk,
331+
fileSystem: fileSystem,
332+
processManager: processManager,
333+
platform: FakePlatform(environment: <String, String>{'HOME': '/home/me'}),
334+
stdio: stdio,
335+
logger: logger,
336+
userMessages: UserMessages(),
337+
androidStudio: FakeAndroidStudio(),
338+
operatingSystemUtils: FakeOperatingSystemUtils(),
339+
);
340+
341+
await licenseValidator.runLicenseManager();
342+
expect(logger.errorText, contains(exceptionMessage));
343+
expect(processManager, hasNoRemainingExpectations);
344+
});
345+
314346
testWithoutContext('runLicenseManager errors when sdkmanager fails to run', () async {
315347
sdk.sdkManagerPath = '/foo/bar/sdkmanager';
316348
processManager.excludedExecutables.add('/foo/bar/sdkmanager');
@@ -574,3 +606,14 @@ class FakeAndroidStudio extends Fake implements AndroidStudio {
574606
@override
575607
String get javaPath => 'java';
576608
}
609+
610+
class ThrowingStdin<T> extends Fake implements IOSink {
611+
ThrowingStdin(this.exception);
612+
613+
final Exception exception;
614+
615+
@override
616+
Future<dynamic> addStream(Stream<List<int>> stream) {
617+
return Future<T>.error(exception);
618+
}
619+
}

0 commit comments

Comments
 (0)