Unverified Commit f796e047 authored by Christopher Fujino's avatar Christopher Fujino Committed by GitHub

Verbose process exceptions (#61552)

parent 9ef81927
...@@ -226,6 +226,7 @@ class _PosixUtils extends OperatingSystemUtils { ...@@ -226,6 +226,7 @@ class _PosixUtils extends OperatingSystemUtils {
_processUtils.runSync( _processUtils.runSync(
<String>['unzip', '-o', '-q', file.path, '-d', targetDirectory.path], <String>['unzip', '-o', '-q', file.path, '-d', targetDirectory.path],
throwOnError: true, throwOnError: true,
verboseExceptions: true,
); );
} }
......
...@@ -231,6 +231,7 @@ abstract class ProcessUtils { ...@@ -231,6 +231,7 @@ abstract class ProcessUtils {
RunResult runSync( RunResult runSync(
List<String> cmd, { List<String> cmd, {
bool throwOnError = false, bool throwOnError = false,
bool verboseExceptions = false,
RunResultChecker allowedFailures, RunResultChecker allowedFailures,
bool hideStdout = false, bool hideStdout = false,
String workingDirectory, String workingDirectory,
...@@ -408,6 +409,7 @@ class _DefaultProcessUtils implements ProcessUtils { ...@@ -408,6 +409,7 @@ class _DefaultProcessUtils implements ProcessUtils {
RunResult runSync( RunResult runSync(
List<String> cmd, { List<String> cmd, {
bool throwOnError = false, bool throwOnError = false,
bool verboseExceptions = false,
RunResultChecker allowedFailures, RunResultChecker allowedFailures,
bool hideStdout = false, bool hideStdout = false,
String workingDirectory, String workingDirectory,
...@@ -449,7 +451,12 @@ class _DefaultProcessUtils implements ProcessUtils { ...@@ -449,7 +451,12 @@ class _DefaultProcessUtils implements ProcessUtils {
} }
if (failedExitCode && throwOnError) { if (failedExitCode && throwOnError) {
runResult.throwException('The command failed'); String message = 'The command failed';
if (verboseExceptions) {
message = 'The command failed\nStdout:\n${runResult.stdout}\n'
'Stderr:\n${runResult.stderr}';
}
runResult.throwException(message);
} }
return runResult; return runResult;
......
...@@ -89,6 +89,31 @@ void main() { ...@@ -89,6 +89,31 @@ void main() {
}); });
}); });
testWithoutContext('If unzip fails, include stderr in exception text', () {
const String exceptionMessage = 'Something really bad happened.';
when(mockProcessManager.runSync(
<String>['unzip', '-o', '-q', null, '-d', null],
)).thenReturn(ProcessResult(0, 1, '', exceptionMessage));
final MockFileSystem fileSystem = MockFileSystem();
final MockFile mockFile = MockFile();
final MockDirectory mockDirectory = MockDirectory();
when(fileSystem.file(any)).thenReturn(mockFile);
when(mockFile.readAsBytesSync()).thenThrow(
const FileSystemException(exceptionMessage),
);
final OperatingSystemUtils osUtils = OperatingSystemUtils(
fileSystem: fileSystem,
logger: BufferLogger.test(),
platform: FakePlatform(operatingSystem: 'linux'),
processManager: mockProcessManager,
);
expect(
() => osUtils.unzip(mockFile, mockDirectory),
throwsProcessException(message: exceptionMessage),
);
});
group('gzip on Windows:', () { group('gzip on Windows:', () {
testWithoutContext('verifyGzip returns false on a FileSystemException', () { testWithoutContext('verifyGzip returns false on a FileSystemException', () {
final MockFileSystem fileSystem = MockFileSystem(); final MockFileSystem fileSystem = MockFileSystem();
...@@ -148,5 +173,6 @@ void main() { ...@@ -148,5 +173,6 @@ void main() {
} }
class MockProcessManager extends Mock implements ProcessManager {} class MockProcessManager extends Mock implements ProcessManager {}
class MockDirectory extends Mock implements Directory {}
class MockFileSystem extends Mock implements FileSystem {} class MockFileSystem extends Mock implements FileSystem {}
class MockFile extends Mock implements File {} class MockFile extends Mock implements File {}
...@@ -286,12 +286,33 @@ void main() { ...@@ -286,12 +286,33 @@ void main() {
expect(processUtils.runSync(<String>['boohoo']).exitCode, 1); expect(processUtils.runSync(<String>['boohoo']).exitCode, 1);
}); });
testWithoutContext(' throws on failure with throwOnError', () async { testWithoutContext('throws on failure with throwOnError', () async {
const String stderr = 'Something went wrong.';
when(mockProcessManager.runSync(<String>['kaboom'])).thenReturn( when(mockProcessManager.runSync(<String>['kaboom'])).thenReturn(
ProcessResult(0, 1, '', '') ProcessResult(0, 1, '', stderr),
);
try {
processUtils.runSync(<String>['kaboom'], throwOnError: true);
fail('ProcessException expected.');
} on ProcessException catch (e) {
expect(e, isA<ProcessException>());
expect(e.message.contains(stderr), false);
}
});
testWithoutContext('throws with stderr in exception on failure with verboseExceptions', () async {
const String stderr = 'Something went wrong.';
when(mockProcessManager.runSync(<String>['verybad'])).thenReturn(
ProcessResult(0, 1, '', stderr),
);
expect(
() => processUtils.runSync(
<String>['verybad'],
throwOnError: true,
verboseExceptions: true,
),
throwsProcessException(message: stderr),
); );
expect(() => processUtils.runSync(<String>['kaboom'], throwOnError: true),
throwsA(isA<ProcessException>()));
}); });
testWithoutContext(' does not throw on allowed Failures', () async { testWithoutContext(' does not throw on allowed Failures', () async {
......
...@@ -13,7 +13,7 @@ import 'package:vm_service/vm_service.dart' as vm_service; ...@@ -13,7 +13,7 @@ import 'package:vm_service/vm_service.dart' as vm_service;
import 'package:flutter_tools/src/base/common.dart'; import 'package:flutter_tools/src/base/common.dart';
import 'package:flutter_tools/src/base/context.dart'; import 'package:flutter_tools/src/base/context.dart';
import 'package:flutter_tools/src/base/file_system.dart'; import 'package:flutter_tools/src/base/file_system.dart';
import 'package:flutter_tools/src/base/process.dart'; import 'package:flutter_tools/src/base/io.dart';
import 'package:flutter_tools/src/commands/create.dart'; import 'package:flutter_tools/src/commands/create.dart';
import 'package:flutter_tools/src/runner/flutter_command.dart'; import 'package:flutter_tools/src/runner/flutter_command.dart';
import 'package:flutter_tools/src/runner/flutter_command_runner.dart'; import 'package:flutter_tools/src/runner/flutter_command_runner.dart';
...@@ -106,15 +106,17 @@ Matcher throwsToolExit({ int exitCode, Pattern message }) { ...@@ -106,15 +106,17 @@ Matcher throwsToolExit({ int exitCode, Pattern message }) {
/// Matcher for [ToolExit]s. /// Matcher for [ToolExit]s.
final test_package.TypeMatcher<ToolExit> isToolExit = isA<ToolExit>(); final test_package.TypeMatcher<ToolExit> isToolExit = isA<ToolExit>();
/// Matcher for functions that throw [ProcessExit]. /// Matcher for functions that throw [ProcessException].
Matcher throwsProcessExit([ dynamic exitCode ]) { Matcher throwsProcessException({ Pattern message }) {
return exitCode == null Matcher matcher = isProcessException;
? throwsA(isProcessExit) if (message != null) {
: throwsA(allOf(isProcessExit, (ProcessExit e) => e.exitCode == exitCode)); matcher = allOf(matcher, (ProcessException e) => e.message?.contains(message));
}
return throwsA(matcher);
} }
/// Matcher for [ProcessExit]s. /// Matcher for [ProcessException]s.
final test_package.TypeMatcher<ProcessExit> isProcessExit = isA<ProcessExit>(); final test_package.TypeMatcher<ProcessException> isProcessException = isA<ProcessException>();
/// Creates a flutter project in the [temp] directory using the /// Creates a flutter project in the [temp] directory using the
/// [arguments] list if specified, or `--no-pub` if not. /// [arguments] list if specified, or `--no-pub` if not.
......
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