[flutter_tools] remove flutter view cache (#56223)

Remove caching of FlutterView. Perhaps the FlutterView RPC might return an empty list if the VM is not quite up yet? We had some old logic to poll the flutter views RPC for up to 200ms. That doesn't seem like a great approach, so instead we could forgo it entirely and trust that either the views come up before the developer tries to interact, or we crash.
This commit is contained in:
Jonah Williams 2020-05-05 10:47:01 -07:00 committed by GitHub
parent a48a51b0ff
commit 209bdcb669
No known key found for this signature in database
GPG key ID: 4AEE18F83AFDEB23
18 changed files with 355 additions and 281 deletions

View file

@ -190,6 +190,11 @@ abstract class ResidentWebRunner extends ResidentRunner {
globals.printStatus('For a more detailed help message, press "h". $quitMessage');
}
@override
Future<List<FlutterView>> listFlutterViews() async {
return <FlutterView>[];
}
@override
Future<void> debugDumpApp() async {
try {

View file

@ -226,38 +226,13 @@ class FlutterDevice {
return completer.future;
}
Future<void> refreshViews() async {
if (vmService == null) {
return;
}
final List<FlutterView> updatedViews = await vmService.getFlutterViews();
_views
..clear()
..addAll(updatedViews);
}
final List<FlutterView> _views = <FlutterView>[];
List<FlutterView> get views {
if (vmService == null) {
return <FlutterView>[];
}
if (viewFilter != null) {
return <FlutterView>[
for (final FlutterView flutterView in _views)
if (flutterView.uiIsolate.name.contains(viewFilter))
flutterView
];
}
return _views;
}
Future<void> exitApps({
@visibleForTesting Duration timeoutDelay = const Duration(seconds: 10),
}) async {
if (!device.supportsFlutterExit) {
return device.stopApp(package);
}
await refreshViews();
final List<FlutterView> views = await vmService.getFlutterViews();
if (views == null || views.isEmpty) {
return device.stopApp(package);
}
@ -333,6 +308,7 @@ class FlutterDevice {
final Uri deviceAssetsDirectoryUri = devFS.baseUri.resolveUri(
globals.fs.path.toUri(getAssetBuildDirectory()));
assert(deviceAssetsDirectoryUri != null);
final List<FlutterView> views = await vmService.getFlutterViews();
await Future.wait<void>(views.map<Future<void>>(
(FlutterView view) => vmService.setAssetDirectory(
assetsDirectory: deviceAssetsDirectoryUri,
@ -343,6 +319,7 @@ class FlutterDevice {
}
Future<void> debugDumpApp() async {
final List<FlutterView> views = await vmService.getFlutterViews();
for (final FlutterView view in views) {
await vmService.flutterDebugDumpApp(
isolateId: view.uiIsolate.id,
@ -351,6 +328,7 @@ class FlutterDevice {
}
Future<void> debugDumpRenderTree() async {
final List<FlutterView> views = await vmService.getFlutterViews();
for (final FlutterView view in views) {
await vmService.flutterDebugDumpRenderTree(
isolateId: view.uiIsolate.id,
@ -359,6 +337,7 @@ class FlutterDevice {
}
Future<void> debugDumpLayerTree() async {
final List<FlutterView> views = await vmService.getFlutterViews();
for (final FlutterView view in views) {
await vmService.flutterDebugDumpLayerTree(
isolateId: view.uiIsolate.id,
@ -367,6 +346,7 @@ class FlutterDevice {
}
Future<void> debugDumpSemanticsTreeInTraversalOrder() async {
final List<FlutterView> views = await vmService.getFlutterViews();
for (final FlutterView view in views) {
await vmService.flutterDebugDumpSemanticsTreeInTraversalOrder(
isolateId: view.uiIsolate.id,
@ -375,6 +355,7 @@ class FlutterDevice {
}
Future<void> debugDumpSemanticsTreeInInverseHitTestOrder() async {
final List<FlutterView> views = await vmService.getFlutterViews();
for (final FlutterView view in views) {
await vmService.flutterDebugDumpSemanticsTreeInInverseHitTestOrder(
isolateId: view.uiIsolate.id,
@ -383,6 +364,7 @@ class FlutterDevice {
}
Future<void> toggleDebugPaintSizeEnabled() async {
final List<FlutterView> views = await vmService.getFlutterViews();
for (final FlutterView view in views) {
await vmService.flutterToggleDebugPaintSizeEnabled(
isolateId: view.uiIsolate.id,
@ -391,6 +373,7 @@ class FlutterDevice {
}
Future<void> toggleDebugCheckElevationsEnabled() async {
final List<FlutterView> views = await vmService.getFlutterViews();
for (final FlutterView view in views) {
await vmService.flutterToggleDebugCheckElevationsEnabled(
isolateId: view.uiIsolate.id,
@ -399,6 +382,7 @@ class FlutterDevice {
}
Future<void> debugTogglePerformanceOverlayOverride() async {
final List<FlutterView> views = await vmService.getFlutterViews();
for (final FlutterView view in views) {
await vmService.flutterTogglePerformanceOverlayOverride(
isolateId: view.uiIsolate.id,
@ -407,6 +391,7 @@ class FlutterDevice {
}
Future<void> toggleWidgetInspector() async {
final List<FlutterView> views = await vmService.getFlutterViews();
for (final FlutterView view in views) {
await vmService.flutterToggleWidgetInspector(
isolateId: view.uiIsolate.id,
@ -415,6 +400,7 @@ class FlutterDevice {
}
Future<void> toggleProfileWidgetBuilds() async {
final List<FlutterView> views = await vmService.getFlutterViews();
for (final FlutterView view in views) {
await vmService.flutterToggleProfileWidgetBuilds(
isolateId: view.uiIsolate.id,
@ -423,6 +409,7 @@ class FlutterDevice {
}
Future<String> togglePlatform({ String from }) async {
final List<FlutterView> views = await vmService.getFlutterViews();
final String to = nextPlatform(from, featureFlags);
for (final FlutterView view in views) {
await vmService.flutterPlatformOverride(
@ -764,15 +751,17 @@ abstract class ResidentRunner {
Future<Map<String, dynamic>> invokeFlutterExtensionRpcRawOnFirstIsolate(
String method, {
Map<String, dynamic> params,
}) {
}) async {
final List<FlutterView> views = await flutterDevices
.first
.vmService.getFlutterViews();
return flutterDevices
.first
.vmService
.invokeFlutterExtensionRpcRaw(
method,
args: params,
isolateId: flutterDevices
.first.views
isolateId: views
.first.uiIsolate.id
);
}
@ -811,13 +800,23 @@ abstract class ResidentRunner {
throw Exception('Canvaskit not supported by this runner.');
}
/// List the attached flutter views.
Future<List<FlutterView>> listFlutterViews() async {
return (await Future.wait(
flutterDevices.map((FlutterDevice d) => d.vmService.getFlutterViews()))
).expand((List<FlutterView> views) => views).toList();
}
/// Write the SkSL shaders to a zip file in build directory.
Future<void> writeSkSL() async {
if (!supportsWriteSkSL) {
throw Exception('writeSkSL is not supported by this runner.');
}
final List<FlutterView> views = await flutterDevices
.first
.vmService.getFlutterViews();
final Map<String, Object> data = await flutterDevices.first.vmService.getSkSLs(
viewId: flutterDevices.first.views.first.id,
viewId: views.first.id,
);
if (data.isEmpty) {
globals.logger.printStatus(
@ -902,78 +901,61 @@ abstract class ResidentRunner {
appFinished();
}
Future<void> refreshViews() async {
final List<Future<void>> futures = <Future<void>>[
for (final FlutterDevice device in flutterDevices) device.refreshViews(),
];
await Future.wait(futures);
}
Future<void> debugDumpApp() async {
await refreshViews();
for (final FlutterDevice device in flutterDevices) {
await device.debugDumpApp();
}
}
Future<void> debugDumpRenderTree() async {
await refreshViews();
for (final FlutterDevice device in flutterDevices) {
await device.debugDumpRenderTree();
}
}
Future<void> debugDumpLayerTree() async {
await refreshViews();
for (final FlutterDevice device in flutterDevices) {
await device.debugDumpLayerTree();
}
}
Future<void> debugDumpSemanticsTreeInTraversalOrder() async {
await refreshViews();
for (final FlutterDevice device in flutterDevices) {
await device.debugDumpSemanticsTreeInTraversalOrder();
}
}
Future<void> debugDumpSemanticsTreeInInverseHitTestOrder() async {
await refreshViews();
for (final FlutterDevice device in flutterDevices) {
await device.debugDumpSemanticsTreeInInverseHitTestOrder();
}
}
Future<void> debugToggleDebugPaintSizeEnabled() async {
await refreshViews();
for (final FlutterDevice device in flutterDevices) {
await device.toggleDebugPaintSizeEnabled();
}
}
Future<void> debugToggleDebugCheckElevationsEnabled() async {
await refreshViews();
for (final FlutterDevice device in flutterDevices) {
await device.toggleDebugCheckElevationsEnabled();
}
}
Future<void> debugTogglePerformanceOverlayOverride() async {
await refreshViews();
for (final FlutterDevice device in flutterDevices) {
await device.debugTogglePerformanceOverlayOverride();
}
}
Future<void> debugToggleWidgetInspector() async {
await refreshViews();
for (final FlutterDevice device in flutterDevices) {
await device.toggleWidgetInspector();
}
}
Future<void> debugToggleProfileWidgetBuilds() async {
await refreshViews();
for (final FlutterDevice device in flutterDevices) {
await device.toggleProfileWidgetBuilds();
}
@ -997,11 +979,12 @@ abstract class ResidentRunner {
'flutter',
'png',
);
final List<FlutterView> views = await device
.vmService.getFlutterViews();
try {
if (supportsServiceProtocol && isRunningDebug) {
await device.refreshViews();
try {
for (final FlutterView view in device.views) {
for (final FlutterView view in views) {
await device.vmService.flutterDebugAllowBanner(
false,
isolateId: view.uiIsolate.id,
@ -1018,7 +1001,7 @@ abstract class ResidentRunner {
} finally {
if (supportsServiceProtocol && isRunningDebug) {
try {
for (final FlutterView view in device.views) {
for (final FlutterView view in views) {
await device.vmService.flutterDebugAllowBanner(
true,
isolateId: view.uiIsolate.id,
@ -1043,9 +1026,10 @@ abstract class ResidentRunner {
}
Future<void> debugTogglePlatform() async {
await refreshViews();
final String isolateId = flutterDevices
.first.views.first.uiIsolate.id;
final List<FlutterView> views = await flutterDevices
.first
.vmService.getFlutterViews();
final String isolateId = views.first.uiIsolate.id;
final String from = await flutterDevices
.first.vmService.flutterPlatformOverride(
isolateId: isolateId,
@ -1078,10 +1062,8 @@ abstract class ResidentRunner {
if (!debuggingOptions.debuggingEnabled) {
throw 'The service protocol is not enabled.';
}
_finished = Completer<int>();
bool viewFound = false;
// Listen for service protocol connection to close.
for (final FlutterDevice device in flutterDevices) {
await device.connect(
reloadSources: reloadSources,
@ -1089,21 +1071,16 @@ abstract class ResidentRunner {
compileExpression: compileExpression,
reloadMethod: reloadMethod,
);
await device.refreshViews();
if (device.views.isNotEmpty) {
viewFound = true;
// This will wait for at least one flutter view before returning.
final Status status = globals.logger.startProgress(
'Waiting for ${device.device.name} to report its views...',
timeout: const Duration(milliseconds: 200),
);
try {
await device.vmService.getFlutterViews();
} finally {
status.stop();
}
}
if (!viewFound) {
if (flutterDevices.length == 1) {
throw 'No Flutter view is available on ${flutterDevices.first.device.name}.';
}
throw 'No Flutter view is available on any device '
'(${flutterDevices.map<String>((FlutterDevice device) => device.device.name).join(', ')}).';
}
// Listen for service protocol connection to close.
for (final FlutterDevice device in flutterDevices) {
// This hooks up callbacks for when the connection stops in the future.
// We don't want to wait for them. We don't handle errors in those callbacks'
// futures either because they just print to logger and is not critical.
@ -1372,8 +1349,7 @@ class TerminalHandler {
}
return false;
case 'l':
final List<FlutterView> views = residentRunner.flutterDevices
.expand((FlutterDevice d) => d.views).toList();
final List<FlutterView> views = await residentRunner.listFlutterViews();
globals.printStatus('Connected ${pluralize('view', views.length)}:');
for (final FlutterView v in views) {
globals.printStatus('${v.uiIsolate.name} (${v.uiIsolate.id})', indent: 2);

View file

@ -95,7 +95,6 @@ class ColdRunner extends ResidentRunner {
continue;
}
await device.initLogReader();
await device.refreshViews();
globals.printTrace('Connected to ${device.device.name}');
}
@ -145,9 +144,9 @@ class ColdRunner extends ResidentRunner {
for (final FlutterDevice device in flutterDevices) {
await device.initLogReader();
}
await refreshViews();
for (final FlutterDevice device in flutterDevices) {
for (final FlutterView view in device.views) {
final List<FlutterView> views = await device.vmService.getFlutterViews();
for (final FlutterView view in views) {
globals.printTrace('Connected to $view.');
}
}

View file

@ -198,7 +198,8 @@ class HotRunner extends ResidentRunner {
}
for (final FlutterDevice device in flutterDevices) {
for (final FlutterView view in device.views) {
final List<FlutterView> views = await device.vmService.getFlutterViews();
for (final FlutterView view in views) {
await device.vmService.flutterFastReassemble(
classId,
isolateId: view.uiIsolate.id,
@ -277,14 +278,14 @@ class HotRunner extends ResidentRunner {
return 3;
}
await refreshViews();
for (final FlutterDevice device in flutterDevices) {
// VM must have accepted the kernel binary, there will be no reload
// report, so we let incremental compiler know that source code was accepted.
if (device.generator != null) {
device.generator.accept();
}
for (final FlutterView view in device.views) {
final List<FlutterView> views = await device.vmService.getFlutterViews();
for (final FlutterView view in views) {
globals.printTrace('Connected to $view.');
}
}
@ -474,15 +475,15 @@ class HotRunner extends ResidentRunner {
Uri main,
Uri assetsDirectory,
) async {
final List<FlutterView> views = await device.vmService.getFlutterViews();
await Future.wait(<Future<void>>[
for (final FlutterView view in device.views)
for (final FlutterView view in views)
device.vmService.runInView(
viewId: view.id,
main: main,
assetsDirectory: assetsDirectory,
),
]);
await device.refreshViews();
}
Future<void> _launchFromDevFS(String mainScript) async {
@ -501,7 +502,8 @@ class HotRunner extends ResidentRunner {
if (benchmarkMode) {
futures.clear();
for (final FlutterDevice device in flutterDevices) {
for (final FlutterView view in device.views) {
final List<FlutterView> views = await device.vmService.getFlutterViews();
for (final FlutterView view in views) {
futures.add(device.vmService
.flushUIThreadTasks(uiIsolateId: view.uiIsolate.id));
}
@ -514,9 +516,6 @@ class HotRunner extends ResidentRunner {
String reason,
bool benchmarkMode = false,
}) async {
globals.printTrace('Refreshing active FlutterViews before restarting.');
await refreshViews();
final Stopwatch restartTimer = Stopwatch()..start();
// TODO(aam): Add generator reset logic once we switch to using incremental
// compiler for full application recompilation on restart.
@ -541,7 +540,8 @@ class HotRunner extends ResidentRunner {
final List<Future<void>> operations = <Future<void>>[];
for (final FlutterDevice device in flutterDevices) {
final Set<String> uiIsolatesIds = <String>{};
for (final FlutterView view in device.views) {
final List<FlutterView> views = await device.vmService.getFlutterViews();
for (final FlutterView view in views) {
if (view.uiIsolate == null) {
continue;
}
@ -810,7 +810,8 @@ class HotRunner extends ResidentRunner {
void Function(String message) onSlow,
}) async {
for (final FlutterDevice device in flutterDevices) {
for (final FlutterView view in device.views) {
final List<FlutterView> views = await device.vmService.getFlutterViews();
for (final FlutterView view in views) {
if (view.uiIsolate == null) {
return OperationResult(2, 'Application isolate not found', fatal: true);
}
@ -818,10 +819,6 @@ class HotRunner extends ResidentRunner {
}
final Stopwatch reloadTimer = Stopwatch()..start();
globals.printTrace('Refreshing active FlutterViews before reloading.');
await refreshViews();
final Stopwatch devFSTimer = Stopwatch()..start();
final UpdateFSReport updatedDevFS = await _updateDevFS();
// Record time it took to synchronize to DevFS.
@ -912,14 +909,6 @@ class HotRunner extends ResidentRunner {
// Record time it took for the VM to reload the sources.
_addBenchmarkData('hotReloadVMReloadMilliseconds', vmReloadTimer.elapsed.inMilliseconds);
final Stopwatch reassembleTimer = Stopwatch()..start();
// Reload the isolate data.
await Future.wait(<Future<void>>[
for (final FlutterDevice device in flutterDevices)
device.refreshViews()
]);
globals.printTrace('Evicting dirty assets');
await _evictDirtyAssets();
// Check if any isolates are paused and reassemble those
@ -930,7 +919,8 @@ class HotRunner extends ResidentRunner {
int pausedIsolatesFound = 0;
bool failedReassemble = false;
for (final FlutterDevice device in flutterDevices) {
for (final FlutterView view in device.views) {
final List<FlutterView> views = await device.vmService.getFlutterViews();
for (final FlutterView view in views) {
// Check if the isolate is paused, and if so, don't reassemble. Ignore the
// PostPauseEvent event - the client requesting the pause will resume the app.
final vm_service.Isolate isolate = await device.vmService
@ -1055,11 +1045,7 @@ class HotRunner extends ResidentRunner {
final StringBuffer message = StringBuffer();
bool plural;
if (pausedIsolatesFound == 1) {
if (flutterDevices.length == 1 && flutterDevices.single.views.length == 1) {
message.write('The application is ');
} else {
message.write('An isolate is ');
}
message.write('The application is ');
plural = false;
} else {
message.write('$pausedIsolatesFound isolates are ');
@ -1121,13 +1107,14 @@ class HotRunner extends ResidentRunner {
}
}
Future<void> _evictDirtyAssets() {
Future<void> _evictDirtyAssets() async {
final List<Future<Map<String, dynamic>>> futures = <Future<Map<String, dynamic>>>[];
for (final FlutterDevice device in flutterDevices) {
if (device.devFS.assetPathsToEvict.isEmpty) {
continue;
}
if (device.views.first.uiIsolate == null) {
final List<FlutterView> views = await device.vmService.getFlutterViews();
if (views.first.uiIsolate == null) {
globals.printError('Application isolate not found for $device');
continue;
}
@ -1136,7 +1123,7 @@ class HotRunner extends ResidentRunner {
device.vmService
.flutterEvictAsset(
assetPath,
isolateId: device.views.first.uiIsolate.id,
isolateId: views.first.uiIsolate.id,
)
);
}

View file

@ -684,15 +684,29 @@ extension FlutterVmService on vm_service.VmService {
}
/// List all [FlutterView]s attached to the current VM.
Future<List<FlutterView>> getFlutterViews() async {
final vm_service.Response response = await callMethod(
kListViewsMethod,
);
final List<Object> rawViews = response.json['views'] as List<Object>;
return <FlutterView>[
for (final Object rawView in rawViews)
FlutterView.parse(rawView as Map<String, Object>)
];
///
/// If this returns an empty list, it will poll forever unless [returnEarly]
/// is set to true.
///
/// By default, the poll duration is 50 milliseconds.
Future<List<FlutterView>> getFlutterViews({
bool returnEarly = false,
Duration delay = const Duration(milliseconds: 50),
}) async {
while (true) {
final vm_service.Response response = await callMethod(
kListViewsMethod,
);
final List<Object> rawViews = response.json['views'] as List<Object>;
final List<FlutterView> views = <FlutterView>[
for (final Object rawView in rawViews)
FlutterView.parse(rawView as Map<String, Object>)
];
if (views.isNotEmpty || returnEarly) {
return views;
}
await Future<void>.delayed(delay);
}
}
/// Attempt to retrieve the isolate with id [isolateId], or `null` if it has

View file

@ -66,7 +66,7 @@ abstract class ChromiumDevice extends Device {
bool get supportsStartPaused => true;
@override
bool get supportsFlutterExit => true;
bool get supportsFlutterExit => false;
@override
bool get supportsScreenshot => false;
@ -343,6 +343,9 @@ class WebServerDevice extends Device {
@override
Future<bool> isLatestBuildInstalled(ApplicationPackage app) async => true;
@override
bool get supportsFlutterExit => false;
@override
Future<bool> get isLocalEmulator async => false;

View file

@ -685,7 +685,6 @@ VMServiceConnector getFakeVmServiceFactory({
final FakeVmServiceHost fakeVmServiceHost = FakeVmServiceHost(
requests: <VmServiceExpectation>[
FakeVmServiceRequest(
id: '1',
method: kListViewsMethod,
args: null,
jsonResponse: <String, Object>{
@ -698,14 +697,12 @@ VMServiceConnector getFakeVmServiceFactory({
},
),
FakeVmServiceRequest(
id: '2',
method: 'getVM',
args: null,
jsonResponse: vm_service.VM.parse(<String, Object>{})
.toJson(),
),
FakeVmServiceRequest(
id: '3',
method: '_createDevFS',
args: <String, Object>{
'fsName': globals.fs.currentDirectory.absolute.path,
@ -715,7 +712,6 @@ VMServiceConnector getFakeVmServiceFactory({
},
),
FakeVmServiceRequest(
id: '4',
method: kListViewsMethod,
args: null,
jsonResponse: <String, Object>{

View file

@ -65,7 +65,7 @@ void main() {
'hotRestart': true,
'screenshot': false,
'fastStart': false,
'flutterExit': true,
'flutterExit': false,
'hardwareRendering': false,
'startPaused': true
}

View file

@ -12,7 +12,6 @@ void main() {
final FakeVmServiceHost fakeVmServiceHost = FakeVmServiceHost(
requests: <VmServiceExpectation>[
FakeVmServiceRequest(
id: '1',
method: 'getVM',
jsonResponse: (vm_service.VM.parse(<String, Object>{})
..isolates = <vm_service.IsolateRef>[
@ -23,7 +22,6 @@ void main() {
).toJson(),
),
const FakeVmServiceRequest(
id: '2',
method: 'getScripts',
args: <String, Object>{
'isolateId': '1',

View file

@ -129,7 +129,6 @@ void main() {
final FakeVmServiceHost fakeVmServiceHost = FakeVmServiceHost(
requests: <VmServiceExpectation>[
FakeVmServiceRequest(
id: '1',
method: '_createDevFS',
args: <String, Object>{
'fsName': 'test',
@ -202,7 +201,6 @@ void main() {
final FakeVmServiceHost fakeVmServiceHost = FakeVmServiceHost(
requests: <VmServiceExpectation>[
FakeVmServiceRequest(
id: '1',
method: '_createDevFS',
args: <String, Object>{
'fsName': 'test',

View file

@ -637,7 +637,6 @@ void main() {
final FakeVmServiceHost fakeVmServiceHost = FakeVmServiceHost(
requests: <VmServiceExpectation>[
FakeVmServiceRequest(
id: '1',
method: kListViewsMethod,
jsonResponse: <String, Object>{
'views': <Object>[

View file

@ -21,6 +21,36 @@ import '../src/common.dart';
import '../src/context.dart';
import '../src/mocks.dart';
final vm_service.Isolate fakeUnpausedIsolate = vm_service.Isolate(
id: '1',
pauseEvent: vm_service.Event(
kind: vm_service.EventKind.kResume,
timestamp: 0
),
breakpoints: <vm_service.Breakpoint>[],
exceptionPauseMode: null,
libraries: <vm_service.LibraryRef>[],
livePorts: 0,
name: 'test',
number: '1',
pauseOnExit: false,
runnable: true,
startTime: 0,
);
final FlutterView fakeFlutterView = FlutterView(
id: 'a',
uiIsolate: fakeUnpausedIsolate,
);
final FakeVmServiceRequest listViews = FakeVmServiceRequest(
method: kListViewsMethod,
jsonResponse: <String, Object>{
'views': <Object>[
fakeFlutterView.toJson(),
],
},
);
void main() {
group('validateReloadReport', () {
testUsingContext('invalid', () async {
@ -172,42 +202,72 @@ void main() {
testUsingContext('Does hot restarts when all devices support it', () async {
final FakeVmServiceHost fakeVmServiceHost = FakeVmServiceHost(requests: <VmServiceExpectation>[
const FakeVmServiceRequest(
id: '1',
method: kListViewsMethod,
jsonResponse: <String, Object>{
'views': <Object>[],
}
),
const FakeVmServiceRequest(
id: '2',
method: kListViewsMethod,
jsonResponse: <String, Object>{
'views': <Object>[],
}
listViews,
FakeVmServiceRequest(
method: 'getIsolate',
args: <String, Object>{
'isolateId': fakeUnpausedIsolate.id,
},
jsonResponse: fakeUnpausedIsolate.toJson(),
),
FakeVmServiceRequest(
id: '3',
method: 'getVM',
jsonResponse: vm_service.VM.parse(<String, Object>{}).toJson()
),
listViews,
FakeVmServiceRequest(
method: 'getIsolate',
args: <String, Object>{
'isolateId': fakeUnpausedIsolate.id,
},
jsonResponse: fakeUnpausedIsolate.toJson(),
),
FakeVmServiceRequest(
id: '4',
method: 'getVM',
jsonResponse: vm_service.VM.parse(<String, Object>{}).toJson()
),
listViews,
listViews,
const FakeVmServiceRequest(
id: '5',
method: kListViewsMethod,
jsonResponse: <String, Object>{
'views': <Object>[],
method: 'streamListen',
args: <String, Object>{
'streamId': 'Isolate',
}
),
const FakeVmServiceRequest(
id: '6',
method: kListViewsMethod,
jsonResponse: <String, Object>{
'views': <Object>[],
method: 'streamListen',
args: <String, Object>{
'streamId': 'Isolate',
}
),
FakeVmServiceStreamResponse(
streamId: 'Isolate',
event: vm_service.Event(
timestamp: 0,
kind: vm_service.EventKind.kIsolateRunnable,
)
),
FakeVmServiceStreamResponse(
streamId: 'Isolate',
event: vm_service.Event(
timestamp: 0,
kind: vm_service.EventKind.kIsolateRunnable,
)
),
FakeVmServiceRequest(
method: kRunInViewMethod,
args: <String, Object>{
'viewId': fakeFlutterView.id,
'mainScript': 'lib/main.dart.dill',
'assetDirectory': 'build/flutter_assets',
}
),
FakeVmServiceRequest(
method: kRunInViewMethod,
args: <String, Object>{
'viewId': fakeFlutterView.id,
'mainScript': 'lib/main.dart.dill',
'assetDirectory': 'build/flutter_assets',
}
),
]);
@ -257,25 +317,40 @@ void main() {
testUsingContext('hot restart supported', () async {
// Setup mocks
final FakeVmServiceHost fakeVmServiceHost = FakeVmServiceHost(requests: <VmServiceExpectation>[
listViews,
FakeVmServiceRequest(
method: 'getIsolate',
args: <String, Object>{
'isolateId': fakeUnpausedIsolate.id,
},
jsonResponse: fakeUnpausedIsolate.toJson(),
),
FakeVmServiceRequest(
method: 'getVM',
jsonResponse: vm_service.VM.parse(<String, Object>{}).toJson(),
),
listViews,
const FakeVmServiceRequest(
id: '1',
method: kListViewsMethod,
jsonResponse: <String, Object>{
'views': <Object>[],
method: 'streamListen',
args: <String, Object>{
'streamId': 'Isolate',
}
),
FakeVmServiceRequest(
id: '2',
method: 'getVM',
jsonResponse: vm_service.VM.parse(<String, Object>{}).toJson()
),
const FakeVmServiceRequest(
id: '3',
method: kListViewsMethod,
jsonResponse: <String, Object>{
'views': <Object>[],
method: kRunInViewMethod,
args: <String, Object>{
'viewId': fakeFlutterView.id,
'mainScript': 'lib/main.dart.dill',
'assetDirectory': 'build/flutter_assets',
}
),
FakeVmServiceStreamResponse(
streamId: 'Isolate',
event: vm_service.Event(
timestamp: 0,
kind: vm_service.EventKind.kIsolateRunnable,
)
),
]);
final MockDevice mockDevice = MockDevice();
when(mockDevice.supportsHotReload).thenReturn(true);

View file

@ -70,6 +70,15 @@ final FlutterView fakeFlutterView = FlutterView(
uiIsolate: fakeUnpausedIsolate,
);
final FakeVmServiceRequest listViews = FakeVmServiceRequest(
method: kListViewsMethod,
jsonResponse: <String, Object>{
'views': <Object>[
fakeFlutterView.toJson(),
],
},
);
void main() {
final Uri testUri = Uri.parse('foo://bar');
Testbed testbed;
@ -127,10 +136,6 @@ void main() {
);
});
when(mockFlutterDevice.devFS).thenReturn(mockDevFS);
when(mockFlutterDevice.views).thenReturn(<FlutterView>[
// NB: still using mock FlutterDevice.
fakeFlutterView,
]);
when(mockFlutterDevice.device).thenReturn(mockDevice);
when(mockFlutterDevice.stopEchoingDeviceLog()).thenAnswer((Invocation invocation) async { });
when(mockFlutterDevice.observatoryUris).thenAnswer((_) => Stream<Uri>.value(testUri));
@ -146,7 +151,6 @@ void main() {
when(mockFlutterDevice.vmService).thenAnswer((Invocation invocation) {
return fakeVmServiceHost.vmService;
});
when(mockFlutterDevice.refreshViews()).thenAnswer((Invocation invocation) async { });
when(mockFlutterDevice.reloadSources(any, pause: anyNamed('pause'))).thenAnswer((Invocation invocation) async {
return <Future<vm_service.ReloadReport>>[
Future<vm_service.ReloadReport>.value(vm_service.ReloadReport.parse(<String, dynamic>{
@ -166,15 +170,7 @@ void main() {
test('FlutterDevice can list views with a filter', () => testbed.run(() async {
fakeVmServiceHost = FakeVmServiceHost(requests: <VmServiceExpectation>[
FakeVmServiceRequest(
id: '1',
method: kListViewsMethod,
jsonResponse: <String, Object>{
'views': <Object>[
fakeFlutterView.toJson(),
],
},
),
listViews,
]);
final MockDevice mockDevice = MockDevice();
final FlutterDevice flutterDevice = FlutterDevice(
@ -184,14 +180,13 @@ void main() {
);
flutterDevice.vmService = fakeVmServiceHost.vmService;
await flutterDevice.refreshViews();
expect(flutterDevice.views, isEmpty);
}));
test('ResidentRunner can attach to device successfully', () => testbed.run(() async {
fakeVmServiceHost = FakeVmServiceHost(requests: <VmServiceExpectation>[]);
fakeVmServiceHost = FakeVmServiceHost(requests: <VmServiceExpectation>[
listViews,
listViews,
]);
final Completer<DebugConnectionInfo> onConnectionInfo = Completer<DebugConnectionInfo>.sync();
final Completer<void> onAppStart = Completer<void>.sync();
final Future<int> result = residentRunner.attach(
@ -207,12 +202,15 @@ void main() {
expect(onConnectionInfo.isCompleted, true);
expect((await connectionInfo).baseUri, 'foo://bar');
expect(onAppStart.isCompleted, true);
expect(fakeVmServiceHost.hasRemainingExpectations, false);
}));
test('ResidentRunner can attach to device successfully with --fast-start', () => testbed.run(() async {
fakeVmServiceHost = FakeVmServiceHost(requests: <VmServiceExpectation>[
listViews,
listViews,
listViews,
FakeVmServiceRequest(
id: '1',
method: 'getIsolate',
args: <String, Object>{
'isolateId': fakeUnpausedIsolate.id,
@ -220,19 +218,17 @@ void main() {
jsonResponse: fakeUnpausedIsolate.toJson(),
),
FakeVmServiceRequest(
id: '2',
method: 'getVM',
jsonResponse: vm_service.VM.parse(<String, Object>{}).toJson(),
),
listViews,
const FakeVmServiceRequest(
id: '3',
method: 'streamListen',
args: <String, Object>{
'streamId': 'Isolate',
}
),
FakeVmServiceRequest(
id: '4',
method: kRunInViewMethod,
args: <String, Object>{
'viewId': fakeFlutterView.id,
@ -284,10 +280,15 @@ void main() {
expect(onConnectionInfo.isCompleted, true);
expect((await connectionInfo).baseUri, 'foo://bar');
expect(onAppStart.isCompleted, true);
expect(fakeVmServiceHost.hasRemainingExpectations, false);
}));
test('ResidentRunner can handle an RPC exception from hot reload', () => testbed.run(() async {
fakeVmServiceHost = FakeVmServiceHost(requests: <VmServiceExpectation>[]);
fakeVmServiceHost = FakeVmServiceHost(requests: <VmServiceExpectation>[
listViews,
listViews,
listViews,
]);
when(mockDevice.sdkNameAndVersion).thenAnswer((Invocation invocation) async {
return 'Example';
});
@ -329,15 +330,18 @@ void main() {
cdKey(CustomDimensions.hotEventEmulator): 'false',
cdKey(CustomDimensions.hotEventFullRestart): 'false',
})).called(1);
expect(fakeVmServiceHost.hasRemainingExpectations, false);
}, overrides: <Type, Generator>{
Usage: () => MockUsage(),
}));
test('ResidentRunner can send target platform to analytics from hot reload', () => testbed.run(() async {
fakeVmServiceHost = FakeVmServiceHost(requests: <VmServiceExpectation>[
// Not all requests are present due to existing mocks
listViews,
listViews,
listViews,
listViews,
FakeVmServiceRequest(
id: '1',
method: 'getIsolate',
args: <String, Object>{
'isolateId': '1',
@ -345,7 +349,6 @@ void main() {
jsonResponse: fakeUnpausedIsolate.toJson(),
),
FakeVmServiceRequest(
id: '2',
method: 'ext.flutter.reassemble',
args: <String, Object>{
'isolateId': fakeUnpausedIsolate.id,
@ -381,10 +384,11 @@ void main() {
}));
test('ResidentRunner can send target platform to analytics from full restart', () => testbed.run(() async {
// Not all requests are present due to existing mocks
fakeVmServiceHost = FakeVmServiceHost(requests: <VmServiceExpectation>[
listViews,
listViews,
listViews,
FakeVmServiceRequest(
id: '1',
method: 'getIsolate',
args: <String, Object>{
'isolateId': fakeUnpausedIsolate.id,
@ -392,19 +396,17 @@ void main() {
jsonResponse: fakeUnpausedIsolate.toJson(),
),
FakeVmServiceRequest(
id: '2',
method: 'getVM',
jsonResponse: vm_service.VM.parse(<String, Object>{}).toJson(),
),
listViews,
const FakeVmServiceRequest(
id: '3',
method: 'streamListen',
args: <String, Object>{
'streamId': 'Isolate',
},
),
FakeVmServiceRequest(
id: '4',
method: kRunInViewMethod,
args: <String, Object>{
'viewId': fakeFlutterView.id,
@ -445,12 +447,16 @@ void main() {
containsPair(cdKey(CustomDimensions.hotEventTargetPlatform),
getNameForTargetPlatform(TargetPlatform.android_arm)),
);
expect(fakeVmServiceHost.hasRemainingExpectations, false);
}, overrides: <Type, Generator>{
Usage: () => MockUsage(),
}));
test('ResidentRunner Can handle an RPC exception from hot restart', () => testbed.run(() async {
fakeVmServiceHost = FakeVmServiceHost(requests: <VmServiceExpectation>[]);
fakeVmServiceHost = FakeVmServiceHost(requests: <VmServiceExpectation>[
listViews,
listViews,
]);
when(mockDevice.sdkNameAndVersion).thenAnswer((Invocation invocation) async {
return 'Example';
});
@ -493,6 +499,7 @@ void main() {
cdKey(CustomDimensions.hotEventEmulator): 'false',
cdKey(CustomDimensions.hotEventFullRestart): 'true',
})).called(1);
expect(fakeVmServiceHost.hasRemainingExpectations, false);
}, overrides: <Type, Generator>{
Usage: () => MockUsage(),
}));
@ -578,14 +585,15 @@ void main() {
test('ResidentRunner does support CanvasKit', () => testbed.run(() async {
fakeVmServiceHost = FakeVmServiceHost(requests: <VmServiceExpectation>[]);
expect(() => residentRunner.toggleCanvaskit(),
throwsA(isA<Exception>()));
}));
test('ResidentRunner handles writeSkSL returning no data', () => testbed.run(() async {
fakeVmServiceHost = FakeVmServiceHost(requests: <VmServiceExpectation>[
FakeVmServiceRequest(
id: '1',
listViews,
FakeVmServiceRequest(
method: kGetSkSLsMethod,
args: <String, Object>{
'viewId': fakeFlutterView.id,
@ -593,17 +601,18 @@ void main() {
jsonResponse: <String, Object>{
'SkSLs': <String, Object>{}
}
)
),
]);
await residentRunner.writeSkSL();
expect(testLogger.statusText, contains('No data was receieved'));
expect(fakeVmServiceHost.hasRemainingExpectations, false);
}));
test('ResidentRunner can write SkSL data to a unique file with engine revision, platform, and device name', () => testbed.run(() async {
fakeVmServiceHost = FakeVmServiceHost(requests: <VmServiceExpectation>[
listViews,
FakeVmServiceRequest(
id: '1',
method: kGetSkSLsMethod,
args: <String, Object>{
'viewId': fakeFlutterView.id,
@ -634,8 +643,8 @@ void main() {
test('ResidentRunner can take screenshot on debug device', () => testbed.run(() async {
fakeVmServiceHost = FakeVmServiceHost(requests: <VmServiceExpectation>[
listViews,
FakeVmServiceRequest(
id: '1',
method: 'ext.flutter.debugAllowBanner',
args: <String, Object>{
'isolateId': fakeUnpausedIsolate.id,
@ -643,7 +652,6 @@ void main() {
},
),
FakeVmServiceRequest(
id: '2',
method: 'ext.flutter.debugAllowBanner',
args: <String, Object>{
'isolateId': fakeUnpausedIsolate.id,
@ -676,8 +684,8 @@ void main() {
test('ResidentRunner bails taking screenshot on debug device if debugAllowBanner throws RpcError', () => testbed.run(() async {
fakeVmServiceHost = FakeVmServiceHost(requests: <VmServiceExpectation>[
listViews,
FakeVmServiceRequest(
id: '1',
method: 'ext.flutter.debugAllowBanner',
args: <String, Object>{
'isolateId': fakeUnpausedIsolate.id,
@ -696,8 +704,8 @@ void main() {
test('ResidentRunner bails taking screenshot on debug device if debugAllowBanner during second request', () => testbed.run(() async {
fakeVmServiceHost = FakeVmServiceHost(requests: <VmServiceExpectation>[
listViews,
FakeVmServiceRequest(
id: '1',
method: 'ext.flutter.debugAllowBanner',
args: <String, Object>{
'isolateId': fakeUnpausedIsolate.id,
@ -705,7 +713,6 @@ void main() {
},
),
FakeVmServiceRequest(
id: '2',
method: 'ext.flutter.debugAllowBanner',
args: <String, Object>{
'isolateId': fakeUnpausedIsolate.id,
@ -719,12 +726,13 @@ void main() {
await residentRunner.screenshot(mockFlutterDevice);
expect(testLogger.errorText, contains('Error'));
expect(fakeVmServiceHost.hasRemainingExpectations, false);
}));
test('ResidentRunner bails taking screenshot on debug device if takeScreenshot throws', () => testbed.run(() async {
fakeVmServiceHost = FakeVmServiceHost(requests: <VmServiceExpectation>[
listViews,
FakeVmServiceRequest(
id: '1',
method: 'ext.flutter.debugAllowBanner',
args: <String, Object>{
'isolateId': fakeUnpausedIsolate.id,
@ -732,7 +740,6 @@ void main() {
},
),
FakeVmServiceRequest(
id: '2',
method: 'ext.flutter.debugAllowBanner',
args: <String, Object>{
'isolateId': fakeUnpausedIsolate.id,
@ -754,10 +761,13 @@ void main() {
expect(() => residentRunner.screenshot(mockFlutterDevice),
throwsAssertionError);
expect(fakeVmServiceHost.hasRemainingExpectations, false);
}));
test('ResidentRunner does not toggle banner in non-debug mode', () => testbed.run(() async {
fakeVmServiceHost = FakeVmServiceHost(requests: <VmServiceExpectation>[]);
fakeVmServiceHost = FakeVmServiceHost(requests: <VmServiceExpectation>[
listViews,
]);
residentRunner = HotRunner(
<FlutterDevice>[
mockFlutterDevice,
@ -781,7 +791,6 @@ void main() {
test('FlutterDevice will not exit a paused isolate', () => testbed.run(() async {
fakeVmServiceHost = FakeVmServiceHost(requests: <VmServiceExpectation>[
FakeVmServiceRequest(
id: '1',
method: '_flutter.listViews',
jsonResponse: <String, Object>{
'views': <Object>[
@ -790,7 +799,6 @@ void main() {
},
),
FakeVmServiceRequest(
id: '2',
method: 'getIsolate',
args: <String, Object>{
'isolateId': fakeUnpausedIsolate.id,
@ -800,7 +808,6 @@ void main() {
]);
final TestFlutterDevice flutterDevice = TestFlutterDevice(
mockDevice,
<FlutterView>[ fakeFlutterView ],
);
flutterDevice.vmService = fakeVmServiceHost.vmService;
when(mockDevice.supportsFlutterExit).thenReturn(true);
@ -814,7 +821,6 @@ void main() {
test('FlutterDevice will call stopApp if the exit request times out', () => testbed.run(() async {
fakeVmServiceHost = FakeVmServiceHost(requests: <VmServiceExpectation>[
FakeVmServiceRequest(
id: '1',
method: '_flutter.listViews',
jsonResponse: <String, Object>{
'views': <Object>[
@ -823,7 +829,6 @@ void main() {
},
),
FakeVmServiceRequest(
id: '2',
method: 'getIsolate',
args: <String, Object>{
'isolateId': fakeUnpausedIsolate.id,
@ -831,7 +836,6 @@ void main() {
jsonResponse: fakeUnpausedIsolate.toJson(),
),
FakeVmServiceRequest(
id: '3',
method: 'ext.flutter.exit',
args: <String, Object>{
'isolateId': fakeUnpausedIsolate.id,
@ -842,7 +846,6 @@ void main() {
]);
final TestFlutterDevice flutterDevice = TestFlutterDevice(
mockDevice,
<FlutterView>[ fakeFlutterView ],
);
flutterDevice.vmService = fakeVmServiceHost.vmService;
when(mockDevice.supportsFlutterExit).thenReturn(true);
@ -858,7 +861,6 @@ void main() {
test('FlutterDevice will exit an un-paused isolate', () => testbed.run(() async {
fakeVmServiceHost = FakeVmServiceHost(requests: <VmServiceExpectation>[
FakeVmServiceRequest(
id: '1',
method: kListViewsMethod,
jsonResponse: <String, Object>{
'views': <Object>[
@ -867,7 +869,6 @@ void main() {
},
),
FakeVmServiceRequest(
id: '2',
method: 'getIsolate',
args: <String, Object>{
'isolateId': fakeUnpausedIsolate.id
@ -875,7 +876,6 @@ void main() {
jsonResponse: fakeUnpausedIsolate.toJson(),
),
FakeVmServiceRequest(
id: '3',
method: 'ext.flutter.exit',
args: <String, Object>{
'isolateId': fakeUnpausedIsolate.id,
@ -885,7 +885,6 @@ void main() {
]);
final TestFlutterDevice flutterDevice = TestFlutterDevice(
mockDevice,
<FlutterView> [fakeFlutterView ],
);
flutterDevice.vmService = fakeVmServiceHost.vmService;
@ -897,18 +896,10 @@ void main() {
expect(fakeVmServiceHost.hasRemainingExpectations, false);
}));
test('ResidentRunner refreshViews calls flutter device', () => testbed.run(() async {
fakeVmServiceHost = FakeVmServiceHost(requests: <VmServiceExpectation>[]);
await residentRunner.refreshViews();
verify(mockFlutterDevice.refreshViews()).called(1);
}));
test('ResidentRunner debugDumpApp calls flutter device', () => testbed.run(() async {
fakeVmServiceHost = FakeVmServiceHost(requests: <VmServiceExpectation>[]);
await residentRunner.debugDumpApp();
verify(mockFlutterDevice.refreshViews()).called(1);
verify(mockFlutterDevice.debugDumpApp()).called(1);
}));
@ -916,7 +907,6 @@ void main() {
fakeVmServiceHost = FakeVmServiceHost(requests: <VmServiceExpectation>[]);
await residentRunner.debugDumpRenderTree();
verify(mockFlutterDevice.refreshViews()).called(1);
verify(mockFlutterDevice.debugDumpRenderTree()).called(1);
}));
@ -924,7 +914,6 @@ void main() {
fakeVmServiceHost = FakeVmServiceHost(requests: <VmServiceExpectation>[]);
await residentRunner.debugDumpLayerTree();
verify(mockFlutterDevice.refreshViews()).called(1);
verify(mockFlutterDevice.debugDumpLayerTree()).called(1);
}));
@ -932,7 +921,6 @@ void main() {
fakeVmServiceHost = FakeVmServiceHost(requests: <VmServiceExpectation>[]);
await residentRunner.debugDumpSemanticsTreeInTraversalOrder();
verify(mockFlutterDevice.refreshViews()).called(1);
verify(mockFlutterDevice.debugDumpSemanticsTreeInTraversalOrder()).called(1);
}));
@ -940,7 +928,6 @@ void main() {
fakeVmServiceHost = FakeVmServiceHost(requests: <VmServiceExpectation>[]);
await residentRunner.debugDumpSemanticsTreeInInverseHitTestOrder();
verify(mockFlutterDevice.refreshViews()).called(1);
verify(mockFlutterDevice.debugDumpSemanticsTreeInInverseHitTestOrder()).called(1);
}));
@ -948,7 +935,6 @@ void main() {
fakeVmServiceHost = FakeVmServiceHost(requests: <VmServiceExpectation>[]);
await residentRunner.debugToggleDebugPaintSizeEnabled();
verify(mockFlutterDevice.refreshViews()).called(1);
verify(mockFlutterDevice.toggleDebugPaintSizeEnabled()).called(1);
}));
@ -956,7 +942,6 @@ void main() {
fakeVmServiceHost = FakeVmServiceHost(requests: <VmServiceExpectation>[]);
await residentRunner.debugToggleDebugCheckElevationsEnabled();
verify(mockFlutterDevice.refreshViews()).called(1);
verify(mockFlutterDevice.toggleDebugCheckElevationsEnabled()).called(1);
}));
@ -964,7 +949,6 @@ void main() {
fakeVmServiceHost = FakeVmServiceHost(requests: <VmServiceExpectation>[]);
await residentRunner.debugTogglePerformanceOverlayOverride();
verify(mockFlutterDevice.refreshViews()).called(1);
verify(mockFlutterDevice.debugTogglePerformanceOverlayOverride()).called(1);
}));
@ -972,7 +956,6 @@ void main() {
fakeVmServiceHost = FakeVmServiceHost(requests: <VmServiceExpectation>[]);
await residentRunner.debugToggleWidgetInspector();
verify(mockFlutterDevice.refreshViews()).called(1);
verify(mockFlutterDevice.toggleWidgetInspector()).called(1);
}));
@ -980,12 +963,14 @@ void main() {
fakeVmServiceHost = FakeVmServiceHost(requests: <VmServiceExpectation>[]);
await residentRunner.debugToggleProfileWidgetBuilds();
verify(mockFlutterDevice.refreshViews()).called(1);
verify(mockFlutterDevice.toggleProfileWidgetBuilds()).called(1);
}));
test('HotRunner writes vm service file when providing debugging option', () => testbed.run(() async {
fakeVmServiceHost = FakeVmServiceHost(requests: <VmServiceExpectation>[]);
fakeVmServiceHost = FakeVmServiceHost(requests: <VmServiceExpectation>[
listViews,
listViews,
]);
setWsAddress(testUri, fakeVmServiceHost.vmService);
globals.fs.file(globals.fs.path.join('lib', 'main.dart')).createSync(recursive: true);
residentRunner = HotRunner(
@ -1007,7 +992,10 @@ void main() {
}));
test('HotRunner unforwards device ports', () => testbed.run(() async {
fakeVmServiceHost = FakeVmServiceHost(requests: <VmServiceExpectation>[]);
fakeVmServiceHost = FakeVmServiceHost(requests: <VmServiceExpectation>[
listViews,
listViews,
]);
final MockDevicePortForwarder mockPortForwarder = MockDevicePortForwarder();
when(mockDevice.portForwarder).thenReturn(mockPortForwarder);
globals.fs.file(globals.fs.path.join('lib', 'main.dart')).createSync(recursive: true);
@ -1035,7 +1023,10 @@ void main() {
}));
test('HotRunner handles failure to write vmservice file', () => testbed.run(() async {
fakeVmServiceHost = FakeVmServiceHost(requests: <VmServiceExpectation>[]);
fakeVmServiceHost = FakeVmServiceHost(requests: <VmServiceExpectation>[
listViews,
listViews,
]);
globals.fs.file(globals.fs.path.join('lib', 'main.dart')).createSync(recursive: true);
residentRunner = HotRunner(
<FlutterDevice>[
@ -1053,13 +1044,16 @@ void main() {
await residentRunner.run();
expect(testLogger.errorText, contains('Failed to write vmservice-out-file at foo'));
expect(fakeVmServiceHost.hasRemainingExpectations, false);
}, overrides: <Type, Generator>{
FileSystem: () => ThrowingForwardingFileSystem(MemoryFileSystem()),
}));
test('ColdRunner writes vm service file when providing debugging option', () => testbed.run(() async {
fakeVmServiceHost = FakeVmServiceHost(requests: <VmServiceExpectation>[]);
fakeVmServiceHost = FakeVmServiceHost(requests: <VmServiceExpectation>[
listViews,
]);
globals.fs.file(globals.fs.path.join('lib', 'main.dart')).createSync(recursive: true);
setWsAddress(testUri, fakeVmServiceHost.vmService);
residentRunner = ColdRunner(
@ -1078,6 +1072,7 @@ void main() {
await residentRunner.run();
expect(await globals.fs.file('foo').readAsString(), testUri.toString());
expect(fakeVmServiceHost.hasRemainingExpectations, false);
}));
test('FlutterDevice uses dartdevc configuration when targeting web', () => testbed.run(() async {
@ -1117,7 +1112,6 @@ void main() {
final TestFlutterDevice flutterDevice = TestFlutterDevice(
mockDevice,
<FlutterView>[],
observatoryUris: Stream<Uri>.value(testUri),
);
@ -1153,14 +1147,11 @@ class MockUsage extends Mock implements Usage {}
class MockProcessManager extends Mock implements ProcessManager {}
class TestFlutterDevice extends FlutterDevice {
TestFlutterDevice(Device device, this.views, { Stream<Uri> observatoryUris })
TestFlutterDevice(Device device, { Stream<Uri> observatoryUris })
: super(device, buildInfo: BuildInfo.debug) {
_observatoryUris = observatoryUris;
}
@override
final List<FlutterView> views;
@override
Stream<Uri> get observatoryUris => _observatoryUris;
Stream<Uri> _observatoryUris;

View file

@ -36,14 +36,12 @@ import '../src/testbed.dart';
const List<VmServiceExpectation> kAttachLogExpectations = <VmServiceExpectation>[
FakeVmServiceRequest(
id: '1',
method: 'streamListen',
args: <String, Object>{
'streamId': 'Stdout',
},
),
FakeVmServiceRequest(
id: '2',
method: 'streamListen',
args: <String, Object>{
'streamId': 'Stderr',
@ -53,14 +51,12 @@ const List<VmServiceExpectation> kAttachLogExpectations = <VmServiceExpectation>
const List<VmServiceExpectation> kAttachIsolateExpectations = <VmServiceExpectation>[
FakeVmServiceRequest(
id: '3',
method: 'streamListen',
args: <String, Object>{
'streamId': 'Isolate'
}
),
FakeVmServiceRequest(
id: '4',
method: 'registerService',
args: <String, Object>{
'service': 'reloadSources',
@ -362,7 +358,6 @@ void main() {
...kAttachExpectations,
const FakeVmServiceRequest(
method: 'hotRestart',
id: '5',
jsonResponse: <String, Object>{
'type': 'Success',
}
@ -439,7 +434,6 @@ void main() {
...kAttachExpectations,
const FakeVmServiceRequest(
method: 'hotRestart',
id: '5',
jsonResponse: <String, Object>{
'type': 'Success',
}
@ -670,7 +664,6 @@ void main() {
fakeVmServiceHost = FakeVmServiceHost(requests: <VmServiceExpectation>[
...kAttachExpectations,
const FakeVmServiceRequest(
id: '5',
method: 'hotRestart',
jsonResponse: <String, Object>{
'type': 'Failed',
@ -693,7 +686,6 @@ void main() {
fakeVmServiceHost = FakeVmServiceHost(requests: <VmServiceExpectation>[
...kAttachExpectations,
const FakeVmServiceRequest(
id: '5',
method: 'hotRestart',
// Failed response,
errorCode: RPCErrorCodes.kInternalError,
@ -725,7 +717,6 @@ void main() {
fakeVmServiceHost = FakeVmServiceHost(requests: <VmServiceExpectation>[
...kAttachExpectations,
const FakeVmServiceRequest(
id: '5',
method: 'ext.flutter.debugDumpApp',
args: <String, Object>{
'isolateId': null,
@ -747,7 +738,6 @@ void main() {
fakeVmServiceHost = FakeVmServiceHost(requests: <VmServiceExpectation>[
...kAttachExpectations,
const FakeVmServiceRequest(
id: '5',
method: 'ext.flutter.debugDumpLayerTree',
args: <String, Object>{
'isolateId': null,
@ -769,7 +759,6 @@ void main() {
fakeVmServiceHost = FakeVmServiceHost(requests: <VmServiceExpectation>[
...kAttachExpectations,
const FakeVmServiceRequest(
id: '5',
method: 'ext.flutter.debugDumpRenderTree',
args: <String, Object>{
'isolateId': null,
@ -791,7 +780,6 @@ void main() {
fakeVmServiceHost = FakeVmServiceHost(requests: <VmServiceExpectation>[
...kAttachExpectations,
const FakeVmServiceRequest(
id: '5',
method: 'ext.flutter.debugDumpSemanticsTreeInTraversalOrder',
args: <String, Object>{
'isolateId': null,
@ -813,7 +801,6 @@ void main() {
fakeVmServiceHost = FakeVmServiceHost(requests: <VmServiceExpectation>[
...kAttachExpectations,
const FakeVmServiceRequest(
id: '5',
method: 'ext.flutter.debugDumpSemanticsTreeInInverseHitTestOrder',
args: <String, Object>{
'isolateId': null,
@ -836,7 +823,6 @@ void main() {
fakeVmServiceHost = FakeVmServiceHost(requests: <VmServiceExpectation>[
...kAttachExpectations,
const FakeVmServiceRequest(
id: '5',
method: 'ext.flutter.debugPaint',
args: <String, Object>{
'isolateId': null,
@ -846,7 +832,6 @@ void main() {
},
),
const FakeVmServiceRequest(
id: '6',
method: 'ext.flutter.debugPaint',
args: <String, Object>{
'isolateId': null,
@ -874,7 +859,6 @@ void main() {
fakeVmServiceHost = FakeVmServiceHost(requests: <VmServiceExpectation>[
...kAttachExpectations,
const FakeVmServiceRequest(
id: '5',
method: 'ext.flutter.showPerformanceOverlay',
args: <String, Object>{
'isolateId': null,
@ -884,7 +868,6 @@ void main() {
},
),
const FakeVmServiceRequest(
id: '6',
method: 'ext.flutter.showPerformanceOverlay',
args: <String, Object>{
'isolateId': null,
@ -911,7 +894,6 @@ void main() {
fakeVmServiceHost = FakeVmServiceHost(requests: <VmServiceExpectation>[
...kAttachExpectations,
const FakeVmServiceRequest(
id: '5',
method: 'ext.flutter.inspector.show',
args: <String, Object>{
'isolateId': null,
@ -921,7 +903,6 @@ void main() {
},
),
const FakeVmServiceRequest(
id: '6',
method: 'ext.flutter.inspector.show',
args: <String, Object>{
'isolateId': null,
@ -948,7 +929,6 @@ void main() {
fakeVmServiceHost = FakeVmServiceHost(requests: <VmServiceExpectation>[
...kAttachExpectations,
const FakeVmServiceRequest(
id: '5',
method: 'ext.flutter.profileWidgetBuilds',
args: <String, Object>{
'isolateId': null,
@ -958,7 +938,6 @@ void main() {
},
),
const FakeVmServiceRequest(
id: '6',
method: 'ext.flutter.profileWidgetBuilds',
args: <String, Object>{
'isolateId': null,
@ -985,7 +964,6 @@ void main() {
fakeVmServiceHost = FakeVmServiceHost(requests: <VmServiceExpectation>[
...kAttachExpectations,
const FakeVmServiceRequest(
id: '5',
method: 'ext.flutter.platformOverride',
args: <String, Object>{
'isolateId': null,
@ -995,7 +973,6 @@ void main() {
},
),
const FakeVmServiceRequest(
id: '6',
method: 'ext.flutter.platformOverride',
args: <String, Object>{
'isolateId': null,
@ -1089,14 +1066,12 @@ void main() {
fakeVmServiceHost = FakeVmServiceHost(requests: <VmServiceExpectation>[
...kAttachLogExpectations,
const FakeVmServiceRequest(
id: '3',
method: 'streamListen',
args: <String, Object>{
'streamId': 'Isolate'
}
),
const FakeVmServiceRequest(
id: '4',
method: 'registerService',
args: <String, Object>{
'service': 'reloadSources',

View file

@ -139,7 +139,9 @@ void main() {
final MockFlutterDevice mockFlutterDevice = MockFlutterDevice();
when(mockResidentRunner.isRunningDebug).thenReturn(true);
when(mockResidentRunner.flutterDevices).thenReturn(<FlutterDevice>[mockFlutterDevice]);
when(mockFlutterDevice.views).thenReturn(<FlutterView>[]);
when(mockResidentRunner.listFlutterViews()).thenAnswer((Invocation invocation) async {
return <FlutterView>[];
});
await terminalHandler.processTerminalInput('l');

View file

@ -231,10 +231,10 @@ void main() {
testWithoutContext('runInView forwards arguments correctly', () async {
final FakeVmServiceHost fakeVmServiceHost = FakeVmServiceHost(
requests: <VmServiceExpectation>[
const FakeVmServiceRequest(method: 'streamListen', id: '1', args: <String, Object>{
const FakeVmServiceRequest(method: 'streamListen', args: <String, Object>{
'streamId': 'Isolate'
}),
const FakeVmServiceRequest(method: kRunInViewMethod, id: '2', args: <String, Object>{
const FakeVmServiceRequest(method: kRunInViewMethod, args: <String, Object>{
'viewId': '1234',
'mainScript': 'main.dart',
'assetDirectory': 'flutter_assets/',
@ -256,6 +256,65 @@ void main() {
);
expect(fakeVmServiceHost.hasRemainingExpectations, false);
});
testWithoutContext('getFlutterViews polls until a view is returned', () async {
final FakeVmServiceHost fakeVmServiceHost = FakeVmServiceHost(
requests: <VmServiceExpectation>[
const FakeVmServiceRequest(
method: kListViewsMethod,
jsonResponse: <String, Object>{
'views': <Object>[],
},
),
const FakeVmServiceRequest(
method: kListViewsMethod,
jsonResponse: <String, Object>{
'views': <Object>[],
},
),
const FakeVmServiceRequest(
method: kListViewsMethod,
jsonResponse: <String, Object>{
'views': <Object>[
<String, Object>{
'id': 'a',
'isolate': <String, Object>{},
},
],
},
),
]
);
expect(
await fakeVmServiceHost.vmService.getFlutterViews(
delay: Duration.zero,
),
isNotEmpty,
);
expect(fakeVmServiceHost.hasRemainingExpectations, false);
});
testWithoutContext('getFlutterViews does not poll if returnEarly is true', () async {
final FakeVmServiceHost fakeVmServiceHost = FakeVmServiceHost(
requests: <VmServiceExpectation>[
const FakeVmServiceRequest(
method: kListViewsMethod,
jsonResponse: <String, Object>{
'views': <Object>[],
},
),
]
);
expect(
await fakeVmServiceHost.vmService.getFlutterViews(
returnEarly: true,
),
isEmpty,
);
expect(fakeVmServiceHost.hasRemainingExpectations, false);
});
}
class MockDevice extends Mock implements Device {}

View file

@ -76,7 +76,7 @@ void main() {
expect(chromeDevice.supportsHotReload, true);
expect(chromeDevice.supportsHotRestart, true);
expect(chromeDevice.supportsStartPaused, true);
expect(chromeDevice.supportsFlutterExit, true);
expect(chromeDevice.supportsFlutterExit, false);
expect(chromeDevice.supportsScreenshot, false);
expect(await chromeDevice.isLocalEmulator, false);
expect(chromeDevice.getLogReader(), isA<NoOpDeviceLogReader>());
@ -96,7 +96,7 @@ void main() {
expect(chromeDevice.supportsHotReload, true);
expect(chromeDevice.supportsHotRestart, true);
expect(chromeDevice.supportsStartPaused, true);
expect(chromeDevice.supportsFlutterExit, true);
expect(chromeDevice.supportsFlutterExit, false);
expect(chromeDevice.supportsScreenshot, false);
expect(await chromeDevice.isLocalEmulator, false);
expect(chromeDevice.getLogReader(), isA<NoOpDeviceLogReader>());
@ -114,7 +114,7 @@ void main() {
expect(device.supportsHotReload, true);
expect(device.supportsHotRestart, true);
expect(device.supportsStartPaused, true);
expect(device.supportsFlutterExit, true);
expect(device.supportsFlutterExit, false);
expect(device.supportsScreenshot, false);
expect(await device.isLocalEmulator, false);
expect(device.getLogReader(), isA<NoOpDeviceLogReader>());

View file

@ -239,7 +239,6 @@ class FakeVmServiceHost {
final FakeVmServiceRequest fakeRequest = _requests.removeAt(0) as FakeVmServiceRequest;
expect(request, isA<Map<String, Object>>()
.having((Map<String, Object> request) => request['method'], 'method', fakeRequest.method)
.having((Map<String, Object> request) => request['id'], 'id', fakeRequest.id)
.having((Map<String, Object> request) => request['params'], 'args', fakeRequest.args)
);
if (fakeRequest.close) {
@ -250,13 +249,13 @@ class FakeVmServiceHost {
if (fakeRequest.errorCode == null) {
_input.add(json.encode(<String, Object>{
'jsonrpc': '2.0',
'id': fakeRequest.id,
'id': request['id'],
'result': fakeRequest.jsonResponse ?? <String, Object>{'type': 'Success'},
}));
} else {
_input.add(json.encode(<String, Object>{
'jsonrpc': '2.0',
'id': fakeRequest.id,
'id': request['id'],
'error': <String, Object>{
'code': fakeRequest.errorCode,
}
@ -299,7 +298,6 @@ abstract class VmServiceExpectation {
class FakeVmServiceRequest implements VmServiceExpectation {
const FakeVmServiceRequest({
@required this.method,
@required this.id,
this.args = const <String, Object>{},
this.jsonResponse,
this.errorCode,
@ -307,7 +305,6 @@ class FakeVmServiceRequest implements VmServiceExpectation {
});
final String method;
final String id;
/// When true, the vm service is automatically closed.
final bool close;