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