Unverified Commit 55176c4d authored by Jenn Magder's avatar Jenn Magder Committed by GitHub

Show device diagnostic messages in doctor (#61585)

parent 1d478597
...@@ -770,7 +770,7 @@ class DeviceDomain extends Domain { ...@@ -770,7 +770,7 @@ class DeviceDomain extends Domain {
// Use the device manager discovery so that client provided device types // Use the device manager discovery so that client provided device types
// are usable via the daemon protocol. // are usable via the daemon protocol.
deviceManager.deviceDiscoverers.forEach(addDeviceDiscoverer); globals.deviceManager.deviceDiscoverers.forEach(addDeviceDiscoverer);
} }
void addDeviceDiscoverer(DeviceDiscovery discoverer) { void addDeviceDiscoverer(DeviceDiscovery discoverer) {
......
...@@ -56,7 +56,7 @@ class DevicesCommand extends FlutterCommand { ...@@ -56,7 +56,7 @@ class DevicesCommand extends FlutterCommand {
exitCode: 1); exitCode: 1);
} }
final List<Device> devices = await deviceManager.refreshAllConnectedDevices(timeout: timeout); final List<Device> devices = await globals.deviceManager.refreshAllConnectedDevices(timeout: timeout);
if (boolArg('machine')) { if (boolArg('machine')) {
await printDevicesAsJson(devices); await printDevicesAsJson(devices);
...@@ -84,7 +84,7 @@ class DevicesCommand extends FlutterCommand { ...@@ -84,7 +84,7 @@ class DevicesCommand extends FlutterCommand {
} }
Future<void> _printDiagnostics() async { Future<void> _printDiagnostics() async {
final List<String> diagnostics = await deviceManager.getDeviceDiagnostics(); final List<String> diagnostics = await globals.deviceManager.getDeviceDiagnostics();
if (diagnostics.isNotEmpty) { if (diagnostics.isNotEmpty) {
globals.printStatus(''); globals.printStatus('');
for (final String diagnostic in diagnostics) { for (final String diagnostic in diagnostics) {
......
...@@ -388,6 +388,7 @@ $ex ...@@ -388,6 +388,7 @@ $ex
} }
Future<Device> findTargetDevice() async { Future<Device> findTargetDevice() async {
final DeviceManager deviceManager = globals.deviceManager;
final List<Device> devices = await deviceManager.findTargetDevices(FlutterProject.current()); final List<Device> devices = await deviceManager.findTargetDevices(FlutterProject.current());
if (deviceManager.hasSpecifiedDeviceId) { if (deviceManager.hasSpecifiedDeviceId) {
......
...@@ -342,7 +342,7 @@ class RunCommand extends RunCommandBase { ...@@ -342,7 +342,7 @@ class RunCommand extends RunCommandBase {
if (devices == null) { if (devices == null) {
throwToolExit(null); throwToolExit(null);
} }
if (deviceManager.hasSpecifiedAllDevices && runningWithPrebuiltApplication) { if (globals.deviceManager.hasSpecifiedAllDevices && runningWithPrebuiltApplication) {
throwToolExit('Using -d all with --use-application-binary is not supported'); throwToolExit('Using -d all with --use-application-binary is not supported');
} }
......
...@@ -238,7 +238,7 @@ abstract class DeviceManager { ...@@ -238,7 +238,7 @@ abstract class DeviceManager {
globals.printStatus(globals.userMessages.flutterMultipleDevicesFound); globals.printStatus(globals.userMessages.flutterMultipleDevicesFound);
await Device.printDevices(devices); await Device.printDevices(devices);
final Device chosenDevice = await _chooseOneOfAvailableDevices(devices); final Device chosenDevice = await _chooseOneOfAvailableDevices(devices);
deviceManager.specifiedDeviceId = chosenDevice.id; globals.deviceManager.specifiedDeviceId = chosenDevice.id;
devices = <Device>[chosenDevice]; devices = <Device>[chosenDevice];
} }
} }
......
...@@ -108,8 +108,11 @@ class _DefaultDoctorValidatorsProvider implements DoctorValidatorsProvider { ...@@ -108,8 +108,11 @@ class _DefaultDoctorValidatorsProvider implements DoctorValidatorsProvider {
NoIdeValidator(), NoIdeValidator(),
if (proxyValidator.shouldShow) if (proxyValidator.shouldShow)
proxyValidator, proxyValidator,
if (deviceManager.canListAnything) if (globals.deviceManager.canListAnything)
DeviceValidator(), DeviceValidator(
deviceManager: globals.deviceManager,
userMessages: globals.userMessages,
),
]; ];
return _validators; return _validators;
} }
...@@ -948,31 +951,52 @@ class IntelliJValidatorOnMac extends IntelliJValidator { ...@@ -948,31 +951,52 @@ class IntelliJValidatorOnMac extends IntelliJValidator {
} }
class DeviceValidator extends DoctorValidator { class DeviceValidator extends DoctorValidator {
DeviceValidator() : super('Connected device'); // TODO(jmagman): Make required once g3 rolls and is updated.
DeviceValidator({
DeviceManager deviceManager,
UserMessages userMessages,
}) : _deviceManager = deviceManager ?? globals.deviceManager,
_userMessages = userMessages ?? globals.userMessages,
super('Connected device');
final DeviceManager _deviceManager;
final UserMessages _userMessages;
@override @override
String get slowWarning => 'Scanning for devices is taking a long time...'; String get slowWarning => 'Scanning for devices is taking a long time...';
@override @override
Future<ValidationResult> validate() async { Future<ValidationResult> validate() async {
final List<Device> devices = await deviceManager.getAllConnectedDevices(); final List<Device> devices = await _deviceManager.getAllConnectedDevices();
List<ValidationMessage> messages; List<ValidationMessage> installedMessages = <ValidationMessage>[];
if (devices.isEmpty) { if (devices.isNotEmpty) {
final List<String> diagnostics = await deviceManager.getDeviceDiagnostics(); installedMessages = await Device.descriptions(devices)
if (diagnostics.isNotEmpty) {
messages = diagnostics.map<ValidationMessage>((String message) => ValidationMessage(message)).toList();
} else {
messages = <ValidationMessage>[ValidationMessage.hint(userMessages.devicesMissing)];
}
} else {
messages = await Device.descriptions(devices)
.map<ValidationMessage>((String msg) => ValidationMessage(msg)).toList(); .map<ValidationMessage>((String msg) => ValidationMessage(msg)).toList();
} }
List<ValidationMessage> diagnosticMessages = <ValidationMessage>[];
final List<String> diagnostics = await _deviceManager.getDeviceDiagnostics();
if (diagnostics.isNotEmpty) {
diagnosticMessages = diagnostics.map<ValidationMessage>((String message) => ValidationMessage.hint(message)).toList();
} else if (devices.isEmpty) {
diagnosticMessages = <ValidationMessage>[ValidationMessage.hint(_userMessages.devicesMissing)];
}
if (devices.isEmpty) { if (devices.isEmpty) {
return ValidationResult(ValidationType.notAvailable, messages); return ValidationResult(ValidationType.notAvailable, diagnosticMessages);
} else if (diagnostics.isNotEmpty) {
installedMessages.addAll(diagnosticMessages);
return ValidationResult(
ValidationType.installed,
installedMessages,
statusInfo: _userMessages.devicesAvailable(devices.length)
);
} else { } else {
return ValidationResult(ValidationType.installed, messages, statusInfo: userMessages.devicesAvailable(devices.length)); return ValidationResult(
ValidationType.installed,
installedMessages,
statusInfo: _userMessages.devicesAvailable(devices.length)
);
} }
} }
} }
......
...@@ -24,6 +24,7 @@ import 'base/time.dart'; ...@@ -24,6 +24,7 @@ import 'base/time.dart';
import 'base/user_messages.dart'; import 'base/user_messages.dart';
import 'build_system/build_system.dart'; import 'build_system/build_system.dart';
import 'cache.dart'; import 'cache.dart';
import 'device.dart';
import 'doctor.dart'; import 'doctor.dart';
import 'fuchsia/fuchsia_sdk.dart'; import 'fuchsia/fuchsia_sdk.dart';
import 'ios/ios_workflow.dart'; import 'ios/ios_workflow.dart';
...@@ -49,6 +50,7 @@ OperatingSystemUtils get os => context.get<OperatingSystemUtils>(); ...@@ -49,6 +50,7 @@ OperatingSystemUtils get os => context.get<OperatingSystemUtils>();
PersistentToolState get persistentToolState => PersistentToolState.instance; PersistentToolState get persistentToolState => PersistentToolState.instance;
Signals get signals => context.get<Signals>() ?? LocalSignals.instance; Signals get signals => context.get<Signals>() ?? LocalSignals.instance;
Usage get flutterUsage => context.get<Usage>(); Usage get flutterUsage => context.get<Usage>();
DeviceManager get deviceManager => context.get<DeviceManager>();
FlutterProjectFactory get projectFactory { FlutterProjectFactory get projectFactory {
return context.get<FlutterProjectFactory>() ?? FlutterProjectFactory( return context.get<FlutterProjectFactory>() ?? FlutterProjectFactory(
......
...@@ -892,7 +892,7 @@ abstract class FlutterCommand extends Command<void> { ...@@ -892,7 +892,7 @@ abstract class FlutterCommand extends Command<void> {
globals.printError(userMessages.flutterNoDevelopmentDevice); globals.printError(userMessages.flutterNoDevelopmentDevice);
return null; return null;
} }
final DeviceManager deviceManager = globals.deviceManager;
List<Device> devices = await deviceManager.findTargetDevices(FlutterProject.current()); List<Device> devices = await deviceManager.findTargetDevices(FlutterProject.current());
if (devices.isEmpty && deviceManager.hasSpecifiedDeviceId) { if (devices.isEmpty && deviceManager.hasSpecifiedDeviceId) {
...@@ -946,7 +946,7 @@ abstract class FlutterCommand extends Command<void> { ...@@ -946,7 +946,7 @@ abstract class FlutterCommand extends Command<void> {
} }
if (deviceList.length > 1) { if (deviceList.length > 1) {
globals.printStatus(userMessages.flutterSpecifyDevice); globals.printStatus(userMessages.flutterSpecifyDevice);
deviceList = await deviceManager.getAllConnectedDevices(); deviceList = await globals.deviceManager.getAllConnectedDevices();
globals.printStatus(''); globals.printStatus('');
await Device.printDevices(deviceList); await Device.printDevices(deviceList);
return null; return null;
...@@ -1023,7 +1023,7 @@ mixin DeviceBasedDevelopmentArtifacts on FlutterCommand { ...@@ -1023,7 +1023,7 @@ mixin DeviceBasedDevelopmentArtifacts on FlutterCommand {
// If there are no attached devices, use the default configuration. // If there are no attached devices, use the default configuration.
// Otherwise, only add development artifacts which correspond to a // Otherwise, only add development artifacts which correspond to a
// connected device. // connected device.
final List<Device> devices = await deviceManager.getDevices(); final List<Device> devices = await globals.deviceManager.getDevices();
if (devices.isEmpty) { if (devices.isEmpty) {
return super.requiredArtifacts; return super.requiredArtifacts;
} }
......
...@@ -21,7 +21,6 @@ import '../base/utils.dart'; ...@@ -21,7 +21,6 @@ import '../base/utils.dart';
import '../cache.dart'; import '../cache.dart';
import '../convert.dart'; import '../convert.dart';
import '../dart/package_map.dart'; import '../dart/package_map.dart';
import '../device.dart';
import '../globals.dart' as globals; import '../globals.dart' as globals;
import '../tester/flutter_tester.dart'; import '../tester/flutter_tester.dart';
...@@ -311,7 +310,7 @@ class FlutterCommandRunner extends CommandRunner<void> { ...@@ -311,7 +310,7 @@ class FlutterCommandRunner extends CommandRunner<void> {
} }
// See if the user specified a specific device. // See if the user specified a specific device.
deviceManager.specifiedDeviceId = topLevelResults['device-id'] as String; globals.deviceManager.specifiedDeviceId = topLevelResults['device-id'] as String;
if (topLevelResults['version'] as bool) { if (topLevelResults['version'] as bool) {
globals.flutterUsage.sendCommand('version'); globals.flutterUsage.sendCommand('version');
......
...@@ -11,6 +11,7 @@ import 'package:flutter_tools/src/artifacts.dart'; ...@@ -11,6 +11,7 @@ import 'package:flutter_tools/src/artifacts.dart';
import 'package:flutter_tools/src/cache.dart'; import 'package:flutter_tools/src/cache.dart';
import 'package:flutter_tools/src/commands/devices.dart'; import 'package:flutter_tools/src/commands/devices.dart';
import 'package:flutter_tools/src/device.dart'; import 'package:flutter_tools/src/device.dart';
import 'package:flutter_tools/src/globals.dart' as globals;
import 'package:mockito/mockito.dart'; import 'package:mockito/mockito.dart';
import 'package:process/process.dart'; import 'package:process/process.dart';
...@@ -53,7 +54,7 @@ void main() { ...@@ -53,7 +54,7 @@ void main() {
testUsingContext('get devices\' platform types', () async { testUsingContext('get devices\' platform types', () async {
final List<String> platformTypes = Device.devicesPlatformTypes( final List<String> platformTypes = Device.devicesPlatformTypes(
await deviceManager.getAllConnectedDevices(), await globals.deviceManager.getAllConnectedDevices(),
); );
expect(platformTypes, <String>['android', 'web']); expect(platformTypes, <String>['android', 'web']);
}, overrides: <Type, Generator>{ }, overrides: <Type, Generator>{
......
...@@ -14,8 +14,10 @@ import 'package:flutter_tools/src/base/logger.dart'; ...@@ -14,8 +14,10 @@ import 'package:flutter_tools/src/base/logger.dart';
import 'package:flutter_tools/src/base/platform.dart'; import 'package:flutter_tools/src/base/platform.dart';
import 'package:flutter_tools/src/base/terminal.dart'; import 'package:flutter_tools/src/base/terminal.dart';
import 'package:flutter_tools/src/base/user_messages.dart'; import 'package:flutter_tools/src/base/user_messages.dart';
import 'package:flutter_tools/src/build_info.dart';
import 'package:flutter_tools/src/cache.dart'; import 'package:flutter_tools/src/cache.dart';
import 'package:flutter_tools/src/commands/doctor.dart'; import 'package:flutter_tools/src/commands/doctor.dart';
import 'package:flutter_tools/src/device.dart';
import 'package:flutter_tools/src/doctor.dart'; import 'package:flutter_tools/src/doctor.dart';
import 'package:flutter_tools/src/features.dart'; import 'package:flutter_tools/src/features.dart';
import 'package:flutter_tools/src/globals.dart' as globals; import 'package:flutter_tools/src/globals.dart' as globals;
...@@ -187,6 +189,76 @@ void main() { ...@@ -187,6 +189,76 @@ void main() {
expect(message.message, startsWith('Flutter extension not installed')); expect(message.message, startsWith('Flutter extension not installed'));
expect(message.isError, isTrue); expect(message.isError, isTrue);
}, overrides: noColorTerminalOverride); }, overrides: noColorTerminalOverride);
group('device validator', () {
testWithoutContext('no devices', () async {
final MockDeviceManager mockDeviceManager = MockDeviceManager();
when(mockDeviceManager.getAllConnectedDevices()).thenAnswer(
(Invocation invocation) => Future<List<Device>>.value(<Device>[])
);
when(mockDeviceManager.getDeviceDiagnostics()).thenAnswer(
(Invocation invocation) => Future<List<String>>.value(<String>[])
);
final DeviceValidator deviceValidator = DeviceValidator(
deviceManager: mockDeviceManager,
userMessages: UserMessages(),
);
final ValidationResult result = await deviceValidator.validate();
expect(result.type, ValidationType.notAvailable);
expect(result.messages, const <ValidationMessage>[
ValidationMessage.hint('No devices available'),
]);
expect(result.statusInfo, isNull);
});
testWithoutContext('diagnostic message', () async {
final MockDeviceManager mockDeviceManager = MockDeviceManager();
when(mockDeviceManager.getAllConnectedDevices()).thenAnswer(
(Invocation invocation) => Future<List<Device>>.value(<Device>[])
);
when(mockDeviceManager.getDeviceDiagnostics()).thenAnswer(
(Invocation invocation) => Future<List<String>>.value(<String>['Device locked'])
);
final DeviceValidator deviceValidator = DeviceValidator(
deviceManager: mockDeviceManager,
userMessages: UserMessages(),
);
final ValidationResult result = await deviceValidator.validate();
expect(result.type, ValidationType.notAvailable);
expect(result.messages, const <ValidationMessage>[
ValidationMessage.hint('Device locked'),
]);
expect(result.statusInfo, isNull);
});
testWithoutContext('diagnostic message and devices', () async {
final MockDeviceManager mockDeviceManager = MockDeviceManager();
final MockDevice mockDevice = MockDevice();
when(mockDeviceManager.getAllConnectedDevices()).thenAnswer(
(_) => Future<List<Device>>.value(<Device>[mockDevice])
);
when(mockDeviceManager.getDeviceDiagnostics()).thenAnswer(
(_) => Future<List<String>>.value(<String>['Device locked'])
);
final DeviceValidator deviceValidator = DeviceValidator(
deviceManager: mockDeviceManager,
userMessages: UserMessages(),
);
final ValidationResult result = await deviceValidator.validate();
expect(result.type, ValidationType.installed);
expect(result.messages, const <ValidationMessage>[
ValidationMessage('null (null) • device-id • android • null'),
ValidationMessage.hint('Device locked'),
]);
expect(result.statusInfo, '1 available');
});
});
}); });
group('doctor with overridden validators', () { group('doctor with overridden validators', () {
...@@ -1154,3 +1226,12 @@ class VsCodeValidatorTestTargets extends VsCodeValidator { ...@@ -1154,3 +1226,12 @@ class VsCodeValidatorTestTargets extends VsCodeValidator {
class MockProcessManager extends Mock implements ProcessManager {} class MockProcessManager extends Mock implements ProcessManager {}
class MockArtifacts extends Mock implements Artifacts {} class MockArtifacts extends Mock implements Artifacts {}
class MockPlistParser extends Mock implements PlistParser {} class MockPlistParser extends Mock implements PlistParser {}
class MockDeviceManager extends Mock implements DeviceManager {}
class MockDevice extends Mock implements Device {
MockDevice() {
when(isSupported()).thenReturn(true);
when(id).thenReturn('device-id');
when(isLocalEmulator).thenAnswer((_) => Future<bool>.value(false));
when(targetPlatform).thenAnswer((_) => Future<TargetPlatform>.value(TargetPlatform.android));
}
}
...@@ -208,17 +208,17 @@ void main() { ...@@ -208,17 +208,17 @@ void main() {
globals.fs.file('.packages').writeAsStringSync('\n'); globals.fs.file('.packages').writeAsStringSync('\n');
globals.fs.file('lib/main.dart').createSync(recursive: true); globals.fs.file('lib/main.dart').createSync(recursive: true);
final FakeDevice device = FakeDevice(isLocalEmulator: true); final FakeDevice device = FakeDevice(isLocalEmulator: true);
when(deviceManager.getAllConnectedDevices()).thenAnswer((Invocation invocation) async { when(mockDeviceManager.getAllConnectedDevices()).thenAnswer((Invocation invocation) async {
return <Device>[device]; return <Device>[device];
}); });
when(deviceManager.getDevices()).thenAnswer((Invocation invocation) async { when(mockDeviceManager.getDevices()).thenAnswer((Invocation invocation) async {
return <Device>[device]; return <Device>[device];
}); });
when(deviceManager.findTargetDevices(any)).thenAnswer((Invocation invocation) async { when(mockDeviceManager.findTargetDevices(any)).thenAnswer((Invocation invocation) async {
return <Device>[device]; return <Device>[device];
}); });
when(deviceManager.hasSpecifiedAllDevices).thenReturn(false); when(mockDeviceManager.hasSpecifiedAllDevices).thenReturn(false);
when(deviceManager.deviceDiscoverers).thenReturn(<DeviceDiscovery>[]); when(mockDeviceManager.deviceDiscoverers).thenReturn(<DeviceDiscovery>[]);
final RunCommand command = RunCommand(); final RunCommand command = RunCommand();
applyMocksToCommand(command); applyMocksToCommand(command);
...@@ -231,7 +231,7 @@ void main() { ...@@ -231,7 +231,7 @@ void main() {
}, overrides: <Type, Generator>{ }, overrides: <Type, Generator>{
FileSystem: () => MemoryFileSystem.test(), FileSystem: () => MemoryFileSystem.test(),
ProcessManager: () => FakeProcessManager.any(), ProcessManager: () => FakeProcessManager.any(),
DeviceManager: () => MockDeviceManager(), DeviceManager: () => mockDeviceManager,
Stdio: () => MockStdio(), Stdio: () => MockStdio(),
}); });
...@@ -557,7 +557,7 @@ class TestRunCommand extends RunCommand { ...@@ -557,7 +557,7 @@ class TestRunCommand extends RunCommand {
@override @override
// ignore: must_call_super // ignore: must_call_super
Future<void> validateCommand() async { Future<void> validateCommand() async {
devices = await deviceManager.getDevices(); devices = await globals.deviceManager.getDevices();
} }
} }
......
...@@ -8,10 +8,11 @@ import 'package:args/command_runner.dart'; ...@@ -8,10 +8,11 @@ import 'package:args/command_runner.dart';
import 'package:flutter_tools/src/cache.dart'; import 'package:flutter_tools/src/cache.dart';
import 'package:flutter_tools/src/commands/devices.dart'; import 'package:flutter_tools/src/commands/devices.dart';
import 'package:flutter_tools/src/base/context.dart';
import 'package:flutter_tools/src/base/logger.dart'; import 'package:flutter_tools/src/base/logger.dart';
import 'package:flutter_tools/src/device.dart'; import 'package:flutter_tools/src/device.dart';
import 'package:flutter_tools/src/features.dart'; import 'package:flutter_tools/src/features.dart';
import 'package:flutter_tools/src/base/context.dart'; import 'package:flutter_tools/src/globals.dart' as globals;
import 'package:flutter_tools/src/web/web_device.dart'; import 'package:flutter_tools/src/web/web_device.dart';
import 'package:mockito/mockito.dart'; import 'package:mockito/mockito.dart';
...@@ -39,7 +40,7 @@ void main() { ...@@ -39,7 +40,7 @@ void main() {
}); });
testUsingContext('devices can display via the --machine flag', () async { testUsingContext('devices can display via the --machine flag', () async {
when(deviceManager.refreshAllConnectedDevices()).thenAnswer((Invocation invocation) async { when(globals.deviceManager.refreshAllConnectedDevices()).thenAnswer((Invocation invocation) async {
return <Device>[ return <Device>[
WebServerDevice(logger: BufferLogger.test()), WebServerDevice(logger: BufferLogger.test()),
]; ];
......
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