Unverified Commit 430626d0 authored by Jonah Williams's avatar Jonah Williams Committed by GitHub

[flutter_tools] use existing service implementations for web (#78995)

parent 12880f77
......@@ -8,3 +8,4 @@ linter:
unawaited_futures: true
curly_braces_in_flow_control_structures: true
avoid_catches_without_on_clauses: true
prefer_relative_imports: true
......@@ -138,11 +138,6 @@ class CommandHelp {
'debugDumpRenderTree',
);
late final CommandHelpOption v = _makeOption(
'v',
'Launch DevTools.',
);
late final CommandHelpOption w = _makeOption(
'w',
'Dump widget hierarchy to the console.',
......
......@@ -231,14 +231,15 @@ class ResidentWebRunner extends ResidentRunner {
@override
Future<bool> debugDumpApp() async {
if (!supportsServiceProtocol) {
if (!supportsServiceProtocol || _vmService == null) {
return false;
}
try {
await _vmService
?.flutterDebugDumpApp(
final String data = await _vmService
.flutterDebugDumpApp(
isolateId: null,
);
_logger.printStatus(data);
} on vmservice.RPCError {
// do nothing.
}
......@@ -247,14 +248,15 @@ class ResidentWebRunner extends ResidentRunner {
@override
Future<bool> debugDumpRenderTree() async {
if (!supportsServiceProtocol) {
if (!supportsServiceProtocol || _vmService == null) {
return false;
}
try {
await _vmService
?.flutterDebugDumpRenderTree(
final String data = await _vmService
.flutterDebugDumpRenderTree(
isolateId: null,
);
_logger.printStatus(data);
} on vmservice.RPCError {
// do nothing.
}
......@@ -263,14 +265,15 @@ class ResidentWebRunner extends ResidentRunner {
@override
Future<bool> debugDumpLayerTree() async {
if (!supportsServiceProtocol) {
if (!supportsServiceProtocol || _vmService == null) {
return false;
}
try {
await _vmService
?.flutterDebugDumpLayerTree(
final String data = await _vmService
.flutterDebugDumpLayerTree(
isolateId: null,
);
_logger.printStatus(data);
} on vmservice.RPCError {
// do nothing.
}
......@@ -788,8 +791,6 @@ class ResidentWebRunner extends ResidentRunner {
_stdOutSub = _vmService.service.onStdoutEvent.listen(onLogEvent);
_stdErrSub = _vmService.service.onStderrEvent.listen(onLogEvent);
_extensionEventSub =
_vmService.service.onExtensionEvent.listen(printStructuredErrorLog);
try {
await _vmService.service.streamListen(vmservice.EventStreams.kStdout);
} on vmservice.RPCError {
......@@ -808,18 +809,21 @@ class ResidentWebRunner extends ResidentRunner {
// It is safe to ignore this error because we expect an error to be
// thrown if we're not already subscribed.
}
try {
await _vmService.service.streamListen(vmservice.EventStreams.kExtension);
} on vmservice.RPCError {
// It is safe to ignore this error because we expect an error to be
// thrown if we're not already subscribed.
}
unawaited(_vmService.service.registerService('reloadSources', 'FlutterTools'));
_vmService.service.registerServiceCallback('reloadSources', (Map<String, Object> params) async {
final bool pause = params['pause'] as bool ?? false;
await restart(benchmarkMode: false, pause: pause, fullRestart: false);
return <String, Object>{'type': 'Success'};
});
await setUpVmService(
(String isolateId, {
bool force,
bool pause,
}) async {
await restart(benchmarkMode: false, pause: pause, fullRestart: false);
},
null,
null,
device.device,
null,
printStructuredErrorLog,
_vmService.service,
);
websocketUri = Uri.parse(_connectionResult.debugConnection.uri);
device.vmService = _vmService;
......
......@@ -1403,7 +1403,6 @@ abstract class ResidentRunner {
if (supportsWriteSkSL) {
commandHelp.M.print();
}
commandHelp.v.print();
// `P` should precede `a`
commandHelp.P.print();
commandHelp.a.print();
......
......@@ -10,6 +10,7 @@ import 'package:file/file.dart';
import 'package:meta/meta.dart' show required;
import 'package:vm_service/vm_service.dart' as vm_service;
import 'base/common.dart';
import 'base/context.dart';
import 'base/io.dart' as io;
import 'base/logger.dart';
......@@ -158,8 +159,11 @@ typedef VMServiceConnector = Future<FlutterVmService> Function(Uri httpUri, {
Device device,
});
/// A connection to the Dart VM Service.
vm_service.VmService setUpVmService(
/// Set up the VM Service client by attaching services for each of the provided
/// callbacks.
///
/// All parameters besides [vmService] may be null.
Future<vm_service.VmService> setUpVmService(
ReloadSources reloadSources,
Restart restart,
CompileExpression compileExpression,
......@@ -167,7 +171,11 @@ vm_service.VmService setUpVmService(
GetSkSLMethod skSLMethod,
PrintStructuredErrorLogMethod printStructuredErrorLogMethod,
vm_service.VmService vmService
) {
) async {
// Each service registration requires a request to the attached VM service. Since the
// order of these requests does not mattter, store each future in a list and await
// all at the end of this method.
final List<Future<vm_service.Success>> registrationRequests = <Future<vm_service.Success>>[];
if (reloadSources != null) {
vmService.registerServiceCallback('reloadSources', (Map<String, dynamic> params) async {
final String isolateId = _validateRpcStringParam('reloadSources', params, 'isolateId');
......@@ -182,7 +190,7 @@ vm_service.VmService setUpVmService(
}
};
});
vmService.registerService('reloadSources', 'Flutter Tools');
registrationRequests.add(vmService.registerService('reloadSources', 'Flutter Tools'));
}
if (restart != null) {
......@@ -195,7 +203,7 @@ vm_service.VmService setUpVmService(
}
};
});
vmService.registerService('hotRestart', 'Flutter Tools');
registrationRequests.add(vmService.registerService('hotRestart', 'Flutter Tools'));
}
vmService.registerServiceCallback('flutterVersion', (Map<String, dynamic> params) async {
......@@ -210,7 +218,7 @@ vm_service.VmService setUpVmService(
}
};
});
vmService.registerService('flutterVersion', 'Flutter Tools');
registrationRequests.add(vmService.registerService('flutterVersion', 'Flutter Tools'));
if (compileExpression != null) {
vmService.registerServiceCallback('compileExpression', (Map<String, dynamic> params) async {
......@@ -230,7 +238,7 @@ vm_service.VmService setUpVmService(
'result': <String, dynamic>{'kernelBytes': kernelBytesBase64},
};
});
vmService.registerService('compileExpression', 'Flutter Tools');
registrationRequests.add(vmService.registerService('compileExpression', 'Flutter Tools'));
}
if (device != null) {
vmService.registerServiceCallback('flutterMemoryInfo', (Map<String, dynamic> params) async {
......@@ -242,7 +250,7 @@ vm_service.VmService setUpVmService(
}
};
});
vmService.registerService('flutterMemoryInfo', 'Flutter Tools');
registrationRequests.add(vmService.registerService('flutterMemoryInfo', 'Flutter Tools'));
}
if (skSLMethod != null) {
vmService.registerServiceCallback('flutterGetSkSL', (Map<String, dynamic> params) async {
......@@ -254,16 +262,22 @@ vm_service.VmService setUpVmService(
}
};
});
vmService.registerService('flutterGetSkSL', 'Flutter Tools');
registrationRequests.add(vmService.registerService('flutterGetSkSL', 'Flutter Tools'));
}
if (printStructuredErrorLogMethod != null) {
try {
vmService.streamListen(vm_service.EventStreams.kExtension);
} on vm_service.RPCError {
// It is safe to ignore this error because we expect an error to be
// thrown if we're already subscribed.
}
vmService.onExtensionEvent.listen(printStructuredErrorLogMethod);
// It is safe to ignore this error because we expect an error to be
// thrown if we're already subscribed.
registrationRequests.add(vmService
.streamListen(vm_service.EventStreams.kExtension)
.catchError((dynamic error) {}, test: (dynamic error) => error is vm_service.RPCError)
);
}
try {
await Future.wait(registrationRequests);
} on vm_service.RPCError catch (e) {
throwToolExit('Failed to register service methods on attached VM Service: $e');
}
return vmService;
}
......@@ -319,7 +333,7 @@ Future<FlutterVmService> _connect(
},
);
final vm_service.VmService service = setUpVmService(
final vm_service.VmService service = await setUpVmService(
reloadSources,
restart,
compileExpression,
......
......@@ -73,7 +73,6 @@ void _testMessageLength({
expect(commandHelp.r.toString().length, lessThanOrEqualTo(expectedWidth));
expect(commandHelp.s.toString().length, lessThanOrEqualTo(expectedWidth));
expect(commandHelp.t.toString().length, lessThanOrEqualTo(expectedWidth));
expect(commandHelp.v.toString().length, lessThanOrEqualTo(expectedWidth));
expect(commandHelp.w.toString().length, lessThanOrEqualTo(expectedWidth));
expect(commandHelp.z.toString().length, lessThanOrEqualTo(expectedWidth));
}
......@@ -119,7 +118,6 @@ void main() {
expect(commandHelp.r.toString(), startsWith('\x1B[1mr\x1B[22m'));
expect(commandHelp.s.toString(), startsWith('\x1B[1ms\x1B[22m'));
expect(commandHelp.t.toString(), startsWith('\x1B[1mt\x1B[22m'));
expect(commandHelp.v.toString(), startsWith('\x1B[1mv\x1B[22m'));
expect(commandHelp.w.toString(), startsWith('\x1B[1mw\x1B[22m'));
expect(commandHelp.z.toString(), startsWith('\x1B[1mz\x1B[22m'));
});
......@@ -196,7 +194,6 @@ void main() {
expect(commandHelp.r.toString(), equals('\x1B[1mr\x1B[22m Hot reload. $fire$fire$fire'));
expect(commandHelp.s.toString(), equals('\x1B[1ms\x1B[22m Save a screenshot to flutter.png.'));
expect(commandHelp.t.toString(), equals('\x1B[1mt\x1B[22m Dump rendering tree to the console. \x1B[90m(debugDumpRenderTree)\x1B[39m\x1b[22m'));
expect(commandHelp.v.toString(), equals('\x1B[1mv\x1B[22m Launch DevTools.'));
expect(commandHelp.w.toString(), equals('\x1B[1mw\x1B[22m Dump widget hierarchy to the console. \x1B[90m(debugDumpApp)\x1B[39m\x1b[22m'));
expect(commandHelp.z.toString(), equals('\x1B[1mz\x1B[22m Toggle elevation checker.'));
});
......@@ -223,7 +220,6 @@ void main() {
expect(commandHelp.r.toString(), equals('r Hot reload. $fire$fire$fire'));
expect(commandHelp.s.toString(), equals('s Save a screenshot to flutter.png.'));
expect(commandHelp.t.toString(), equals('t Dump rendering tree to the console. (debugDumpRenderTree)'));
expect(commandHelp.v.toString(), equals('v Launch DevTools.'));
expect(commandHelp.w.toString(), equals('w Dump widget hierarchy to the console. (debugDumpApp)'));
expect(commandHelp.z.toString(), equals('z Toggle elevation checker.'));
});
......
......@@ -1501,7 +1501,6 @@ void main() {
commandHelp.z,
commandHelp.g,
commandHelp.M,
commandHelp.v,
commandHelp.P,
commandHelp.a,
'',
......
......@@ -61,18 +61,32 @@ const List<VmServiceExpectation> kAttachIsolateExpectations = <VmServiceExpectat
}
),
FakeVmServiceRequest(
method: 'streamListen',
method: 'registerService',
args: <String, Object>{
'streamId': 'Extension',
},
'service': 'reloadSources',
'alias': 'Flutter Tools',
}
),
FakeVmServiceRequest(
method: 'registerService',
args: <String, Object>{
'service': 'reloadSources',
'alias': 'FlutterTools',
'service': 'flutterVersion',
'alias': 'Flutter Tools',
}
)
),
FakeVmServiceRequest(
method: 'registerService',
args: <String, Object>{
'service': 'flutterMemoryInfo',
'alias': 'Flutter Tools',
}
),
FakeVmServiceRequest(
method: 'streamListen',
args: <String, Object>{
'streamId': 'Extension',
},
),
];
const List<VmServiceExpectation> kAttachExpectations = <VmServiceExpectation>[
......@@ -480,11 +494,6 @@ void main() {
connectionInfoCompleter: connectionInfoCompleter,
));
await connectionInfoCompleter.future;
// Need these to run events, otherwise expect statements below run before
// structured errors are processed.
await null;
await null;
await null;
expect(testLogger.statusText, contains('\nerror text'));
......
......@@ -9,9 +9,8 @@ import 'dart:async';
import 'package:flutter_tools/src/base/common.dart';
import 'package:flutter_tools/src/base/io.dart' as io;
import 'package:flutter_tools/src/convert.dart';
import 'package:test/fake.dart';
import 'package:vm_service/vm_service.dart' as vm_service;
import 'package:mockito/mockito.dart';
import 'package:flutter_tools/src/base/logger.dart';
import 'package:flutter_tools/src/device.dart';
import 'package:flutter_tools/src/version.dart';
import 'package:flutter_tools/src/vmservice.dart';
......@@ -90,11 +89,11 @@ final FakeVmServiceRequest listViewsRequest = FakeVmServiceRequest(
typedef ServiceCallback = Future<Map<String, dynamic>> Function(Map<String, Object>);
void main() {
testUsingContext('VmService registers reloadSources', () async {
testWithoutContext('VmService registers reloadSources', () async {
Future<void> reloadSources(String isolateId, { bool pause, bool force}) async {}
final MockVMService mockVMService = MockVMService();
setUpVmService(
await setUpVmService(
reloadSources,
null,
null,
......@@ -104,16 +103,14 @@ void main() {
mockVMService,
);
verify(mockVMService.registerService('reloadSources', 'Flutter Tools')).called(1);
}, overrides: <Type, Generator>{
Logger: () => BufferLogger.test()
expect(mockVMService.services, containsPair('reloadSources', 'Flutter Tools'));
});
testUsingContext('VmService registers flutterMemoryInfo service', () async {
testWithoutContext('VmService registers flutterMemoryInfo service', () async {
final FakeDevice mockDevice = FakeDevice();
final MockVMService mockVMService = MockVMService();
setUpVmService(
await setUpVmService(
null,
null,
null,
......@@ -123,14 +120,12 @@ void main() {
mockVMService,
);
verify(mockVMService.registerService('flutterMemoryInfo', 'Flutter Tools')).called(1);
}, overrides: <Type, Generator>{
Logger: () => BufferLogger.test()
expect(mockVMService.services, containsPair('flutterMemoryInfo', 'Flutter Tools'));
});
testUsingContext('VmService registers flutterGetSkSL service', () async {
testWithoutContext('VmService registers flutterGetSkSL service', () async {
final MockVMService mockVMService = MockVMService();
setUpVmService(
await setUpVmService(
null,
null,
null,
......@@ -140,17 +135,42 @@ void main() {
mockVMService,
);
verify(mockVMService.registerService('flutterGetSkSL', 'Flutter Tools')).called(1);
}, overrides: <Type, Generator>{
Logger: () => BufferLogger.test()
expect(mockVMService.services, containsPair('flutterGetSkSL', 'Flutter Tools'));
});
testWithoutContext('VmService throws tool exit on service registration failure.', () async {
final MockVMService mockVMService = MockVMService()
..errorOnRegisterService = true;
await expectLater(() async => setUpVmService(
null,
null,
null,
null,
() async => 'hello',
null,
mockVMService,
), throwsToolExit());
});
testWithoutContext('VmService throws tool exit on service registration failure with awaited future.', () async {
final MockVMService mockVMService = MockVMService()
..errorOnRegisterService = true;
await expectLater(() async => setUpVmService(
null,
null,
null,
null,
() async => 'hello',
(vm_service.Event event) { },
mockVMService,
), throwsToolExit());
});
testUsingContext('VmService registers flutterPrintStructuredErrorLogMethod', () async {
testWithoutContext('VmService registers flutterPrintStructuredErrorLogMethod', () async {
final MockVMService mockVMService = MockVMService();
when(mockVMService.onExtensionEvent).thenAnswer((Invocation invocation) {
return const Stream<vm_service.Event>.empty();
});
setUpVmService(
await setUpVmService(
null,
null,
null,
......@@ -159,14 +179,12 @@ void main() {
(vm_service.Event event) async => 'hello',
mockVMService,
);
verify(mockVMService.streamListen(vm_service.EventStreams.kExtension)).called(1);
}, overrides: <Type, Generator>{
Logger: () => BufferLogger.test()
expect(mockVMService.listenedStreams, contains(vm_service.EventStreams.kExtension));
});
testUsingContext('VMService returns correct FlutterVersion', () async {
testWithoutContext('VMService returns correct FlutterVersion', () async {
final MockVMService mockVMService = MockVMService();
setUpVmService(
await setUpVmService(
null,
null,
null,
......@@ -176,9 +194,7 @@ void main() {
mockVMService,
);
verify(mockVMService.registerService('flutterVersion', 'Flutter Tools')).called(1);
}, overrides: <Type, Generator>{
FlutterVersion: () => FakeFlutterVersion(),
expect(mockVMService.services, containsPair('flutterVersion', 'Flutter Tools'));
});
testUsingContext('VMService prints messages for connection failures', () {
......@@ -629,8 +645,35 @@ void main() {
});
}
class MockVMService extends Mock implements vm_service.VmService {}
class MockVMService extends Fake implements vm_service.VmService {
final Map<String, String> services = <String, String>{};
final Set<String> listenedStreams = <String>{};
bool errorOnRegisterService = false;
@override
void registerServiceCallback(String service, vm_service.ServiceCallback cb) {}
@override
Future<vm_service.Success> registerService(String service, String alias) async {
services[service] = alias;
if (errorOnRegisterService) {
throw vm_service.RPCError('registerService', 1234, 'error');
}
return vm_service.Success();
}
@override
Stream<vm_service.Event> get onExtensionEvent => const Stream<vm_service.Event>.empty();
@override
Future<vm_service.Success> streamListen(String streamId) async {
listenedStreams.add(streamId);
return vm_service.Success();
}
}
class FakeDevice extends Fake implements Device {}
class FakeFlutterVersion extends Fake implements FlutterVersion {
@override
Map<String, Object> toJson() => const <String, Object>{'Fake': 'Version'};
......
......@@ -572,7 +572,6 @@ void main() {
'z Toggle elevation checker.',
'g Run source code generators.',
'M Write SkSL shaders to a unique file in the project directory.',
'v Launch DevTools.', // TODO(ianh): hide this when devtools isn't available
'P Toggle performance overlay. (WidgetsApp.showPerformanceOverlay)',
'a Toggle timeline events for all widget build methods. (debugProfileWidgetBuilds)',
'',
......
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