Revert "[flutter_tools] migrate FlutterView to new vm_service (#55341)" (#55772)

This reverts commit 2e50fd75eb.
This commit is contained in:
Jonah Williams 2020-04-27 14:26:56 -07:00 committed by GitHub
parent 2e50fd75eb
commit 07c451fea9
No known key found for this signature in database
GPG key ID: 4AEE18F83AFDEB23
13 changed files with 368 additions and 533 deletions

View file

@ -620,12 +620,13 @@ class FuchsiaDevice extends Device {
// loopback (::1).
final Uri uri = Uri.parse('http://[$_ipv6Loopback]:$port');
final VMService vmService = await VMService.connect(uri);
final List<FlutterView> flutterViews = await vmService.getFlutterViews();
for (final FlutterView flutterView in flutterViews) {
await vmService.getVMOld();
await vmService.refreshViews();
for (final FlutterView flutterView in vmService.vm.views) {
if (flutterView.uiIsolate == null) {
continue;
}
final Uri address = vmService.httpAddress;
final Uri address = flutterView.owner.vmService.httpAddress;
if (flutterView.uiIsolate.name.contains(isolateName)) {
return address.port;
}
@ -716,12 +717,13 @@ class FuchsiaIsolateDiscoveryProtocol {
continue;
}
}
final List<FlutterView> flutterViews = await service.getFlutterViews();
for (final FlutterView flutterView in flutterViews) {
await service.getVMOld();
await service.refreshViews();
for (final FlutterView flutterView in service.vm.views) {
if (flutterView.uiIsolate == null) {
continue;
}
final Uri address = service.httpAddress;
final Uri address = flutterView.owner.vmService.httpAddress;
if (flutterView.uiIsolate.name.contains(_isolateName)) {
_foundUri.complete(_device.ipv6
? Uri.parse('http://[$_ipv6Loopback]:${address.port}/')

View file

@ -233,25 +233,18 @@ class FlutterDevice {
if (vmService == null) {
return;
}
final List<FlutterView> updatedViews = await vmService.getFlutterViews();
_views
..clear()
..addAll(updatedViews);
await flutterDeprecatedVmService.vm.refreshViews(waitForViews: true);
}
final List<FlutterView> _views = <FlutterView>[];
List<FlutterView> get views {
if (vmService == null) {
if (vmService == null || flutterDeprecatedVmService.isClosed) {
return <FlutterView>[];
}
if (viewFilter != null) {
return <FlutterView>[
for (final FlutterView flutterView in views)
if (flutterView.uiIsolate.name.contains(viewFilter))
flutterView
];
}
return _views;
return (viewFilter != null
? flutterDeprecatedVmService.vm.allViewsWithName(viewFilter)
: flutterDeprecatedVmService.vm.views).toList();
}
Future<void> getVMs() => flutterDeprecatedVmService.getVMOld();
@ -261,32 +254,35 @@ class FlutterDevice {
await device.stopApp(package);
return;
}
await refreshViews();
if (views == null || views.isEmpty) {
final List<FlutterView> flutterViews = views;
if (flutterViews == null || flutterViews.isEmpty) {
return;
}
// If any of the flutter views are paused, we might not be able to
// cleanly exit since the service extension may not have been registered.
for (final FlutterView flutterView in views) {
final vm_service.Isolate isolate = await vmService
.getIsolateOrNull(flutterView.uiIsolate.id);
if (isolate == null) {
continue;
}
if (isPauseEvent(isolate.pauseEvent.kind)) {
await device.stopApp(package);
return;
if (flutterViews.any((FlutterView view) {
return view != null &&
view.uiIsolate != null &&
view.uiIsolate.pauseEvent != null &&
view.uiIsolate.pauseEvent.isPauseEvent;
}
)) {
await device.stopApp(package);
return;
}
for (final FlutterView view in views) {
final List<Future<void>> futures = <Future<void>>[];
for (final FlutterView view in flutterViews) {
if (view != null && view.uiIsolate != null) {
// If successful, there will be no response from flutterExit.
unawaited(vmService.flutterExit(
assert(!view.uiIsolate.pauseEvent.isPauseEvent);
futures.add(vmService.flutterExit(
isolateId: view.uiIsolate.id,
));
}
}
return vmService.onDone;
// The flutterExit message only returns if it fails, so just wait a few
// seconds then assume it worked.
// TODO(ianh): We should make this return once the VM service disconnects.
await Future.wait(futures).timeout(const Duration(seconds: 2), onTimeout: () => <void>[]);
}
Future<Uri> setupDevFS(

View file

@ -514,8 +514,10 @@ class HotRunner extends ResidentRunner {
String reason,
bool benchmarkMode = false,
}) async {
globals.printTrace('Refreshing active FlutterViews before restarting.');
await refreshViews();
if (!_isPaused()) {
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
@ -540,36 +542,31 @@ class HotRunner extends ResidentRunner {
// Check if the isolate is paused and resume it.
final List<Future<void>> operations = <Future<void>>[];
for (final FlutterDevice device in flutterDevices) {
final Set<String> uiIsolatesIds = <String>{};
final Set<Isolate> uiIsolates = <Isolate>{};
for (final FlutterView view in device.views) {
if (view.uiIsolate == null) {
continue;
}
uiIsolatesIds.add(view.uiIsolate.id);
uiIsolates.add(view.uiIsolate);
// Reload the isolate.
final Future<vm_service.Isolate> reloadIsolate = device.vmService
.getIsolateOrNull(view.uiIsolate.id);
operations.add(reloadIsolate.then((vm_service.Isolate isolate) async {
if ((isolate != null) && isPauseEvent(isolate.pauseEvent.kind)) {
operations.add(view.uiIsolate.reload().then((ServiceObject _) {
final ServiceEvent pauseEvent = view.uiIsolate.pauseEvent;
if ((pauseEvent != null) && pauseEvent.isPauseEvent) {
// Resume the isolate so that it can be killed by the embedder.
await device.vmService.resume(view.uiIsolate.id);
return device.vmService.resume(view.uiIsolate.id);
}
return null;
}));
}
// The engine handles killing and recreating isolates that it has spawned
// ("uiIsolates"). The isolates that were spawned from these uiIsolates
// will not be restared, and so they must be manually killed.
final vm_service.VM vm = await device.vmService.getVM();
for (final vm_service.IsolateRef isolateRef in vm.isolates) {
if (uiIsolatesIds.contains(isolateRef.id)) {
continue;
for (final Isolate isolate in device?.flutterDeprecatedVmService?.vm?.isolates ?? <Isolate>[]) {
if (!uiIsolates.contains(isolate)) {
operations.add(isolate.invokeRpcRaw('kill', params: <String, dynamic>{
'isolateId': isolate.id,
}));
}
operations.add(device.vmService.kill(isolateRef.id)
.catchError((dynamic error, StackTrace stackTrace) {
// Do nothing on a SentinelException since it means the isolate
// has already been killed.
}, test: (dynamic error) => error is vm_service.SentinelException));
}
}
await Future.wait(operations);
@ -592,11 +589,13 @@ class HotRunner extends ResidentRunner {
} on vm_service.RPCError {
// Do nothing, we're already subcribed.
}
isolateNotifications.add(
device.vmService.onIsolateEvent.firstWhere((vm_service.Event event) {
return event.kind == vm_service.EventKind.kIsolateRunnable;
}),
);
for (final FlutterView view in device.views) {
isolateNotifications.add(
view.owner.vm.vmService.onIsolateEvent.firstWhere((vm_service.Event event) {
return event.kind == vm_service.EventKind.kIsolateRunnable;
}),
);
}
}
await Future.wait(isolateNotifications);
}
@ -819,9 +818,11 @@ class HotRunner extends ResidentRunner {
final Stopwatch reloadTimer = Stopwatch()..start();
globals.printTrace('Refreshing active FlutterViews before reloading.');
await refreshVM();
await refreshViews();
if (!_isPaused()) {
globals.printTrace('Refreshing active FlutterViews before reloading.');
await refreshVM();
await refreshViews();
}
final Stopwatch devFSTimer = Stopwatch()..start();
final UpdateFSReport updatedDevFS = await _updateDevFS();
@ -913,19 +914,27 @@ 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()
]);
// Reload the isolate.
final List<Future<void>> allDevices = <Future<void>>[];
for (final FlutterDevice device in flutterDevices) {
globals.printTrace('Sending reload events to ${device.device.name}');
final List<Future<ServiceObject>> futuresViews = <Future<ServiceObject>>[];
for (final FlutterView view in device.views) {
globals.printTrace('Sending reload event to "${view.uiIsolate.name}"');
futuresViews.add(view.uiIsolate.reload());
}
allDevices.add(Future.wait(futuresViews).whenComplete(() {
return device.refreshViews();
}));
}
await Future.wait(allDevices);
globals.printTrace('Evicting dirty assets');
await _evictDirtyAssets();
// Check if any isolates are paused and reassemble those
// that aren't.
final Map<FlutterView, vm_service.VmService> reassembleViews = <FlutterView, vm_service.VmService>{};
final List<FlutterView> reassembleViews = <FlutterView>[];
final List<Future<void>> reassembleFutures = <Future<void>>[];
String serviceEventKind;
int pausedIsolatesFound = 0;
@ -934,12 +943,8 @@ class HotRunner extends ResidentRunner {
for (final FlutterView view in device.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
.getIsolateOrNull(view.uiIsolate.id);
final vm_service.Event pauseEvent = isolate?.pauseEvent;
if (pauseEvent != null
&& isPauseEvent(pauseEvent.kind)
&& pauseEvent.kind != vm_service.EventKind.kPausePostRequest) {
final ServiceEvent pauseEvent = view.uiIsolate.pauseEvent;
if (pauseEvent != null && pauseEvent.isPauseEvent && pauseEvent.kind != ServiceEvent.kPausePostRequest) {
pausedIsolatesFound += 1;
if (serviceEventKind == null) {
serviceEventKind = pauseEvent.kind;
@ -947,7 +952,7 @@ class HotRunner extends ResidentRunner {
serviceEventKind = ''; // many kinds
}
} else {
reassembleViews[view] = device.vmService;
reassembleViews.add(view);
reassembleFutures.add(device.vmService.flutterReassemble(
isolateId: view.uiIsolate.id,
).catchError((dynamic error) {
@ -969,7 +974,6 @@ class HotRunner extends ResidentRunner {
assert(reassembleViews.isNotEmpty);
globals.printTrace('Reassembling application');
final Future<void> reassembleFuture = Future.wait<void>(reassembleFutures);
await reassembleFuture.timeout(
const Duration(seconds: 2),
@ -982,17 +986,14 @@ class HotRunner extends ResidentRunner {
globals.printTrace('This is taking a long time; will now check for paused isolates.');
int postReloadPausedIsolatesFound = 0;
String serviceEventKind;
for (final FlutterView view in reassembleViews.keys) {
final vm_service.Isolate isolate = await reassembleViews[view]
.getIsolateOrNull(view.uiIsolate.id);
if (isolate == null) {
continue;
}
if (isolate.pauseEvent != null && isPauseEvent(isolate.pauseEvent.kind)) {
for (final FlutterView view in reassembleViews) {
await view.uiIsolate.reload();
final ServiceEvent pauseEvent = view.uiIsolate.pauseEvent;
if (pauseEvent != null && pauseEvent.isPauseEvent) {
postReloadPausedIsolatesFound += 1;
if (serviceEventKind == null) {
serviceEventKind = isolate.pauseEvent.kind;
} else if (serviceEventKind != isolate.pauseEvent.kind) {
serviceEventKind = pauseEvent.kind;
} else if (serviceEventKind != pauseEvent.kind) {
serviceEventKind = ''; // many kinds
}
}
@ -1068,33 +1069,32 @@ class HotRunner extends ResidentRunner {
}
assert(serviceEventKind != null);
switch (serviceEventKind) {
case vm_service.EventKind.kPauseStart:
message.write('paused (probably due to --start-paused)');
break;
case vm_service.EventKind.kPauseExit:
message.write('paused because ${ plural ? 'they have' : 'it has' } terminated');
break;
case vm_service.EventKind.kPauseBreakpoint:
message.write('paused in the debugger on a breakpoint');
break;
case vm_service.EventKind.kPauseInterrupted:
message.write('paused due in the debugger');
break;
case vm_service.EventKind.kPauseException:
message.write('paused in the debugger after an exception was thrown');
break;
case vm_service.EventKind.kPausePostRequest:
message.write('paused');
break;
case '':
message.write('paused for various reasons');
break;
case ServiceEvent.kPauseStart: message.write('paused (probably due to --start-paused)'); break;
case ServiceEvent.kPauseExit: message.write('paused because ${ plural ? 'they have' : 'it has' } terminated'); break;
case ServiceEvent.kPauseBreakpoint: message.write('paused in the debugger on a breakpoint'); break;
case ServiceEvent.kPauseInterrupted: message.write('paused due in the debugger'); break;
case ServiceEvent.kPauseException: message.write('paused in the debugger after an exception was thrown'); break;
case ServiceEvent.kPausePostRequest: message.write('paused'); break;
case '': message.write('paused for various reasons'); break;
default:
message.write('paused');
}
return message.toString();
}
bool _isPaused() {
for (final FlutterDevice device in flutterDevices) {
for (final FlutterView view in device.views) {
if (view.uiIsolate != null) {
final ServiceEvent pauseEvent = view.uiIsolate.pauseEvent;
if (pauseEvent != null && pauseEvent.isPauseEvent) {
return true;
}
}
}
}
return false;
}
@override
void printHelp({ @required bool details }) {
@ -1134,7 +1134,7 @@ class HotRunner extends ResidentRunner {
}
for (final String assetPath in device.devFS.assetPathsToEvict) {
futures.add(
device.vmService
device.views.first.uiIsolate.vmService
.flutterEvictAsset(
assetPath,
isolateId: device.views.first.uiIsolate.id,

View file

@ -53,9 +53,8 @@ class Tracing {
}
});
bool done = false;
final List<FlutterView> views = await vmService.getFlutterViews();
for (final FlutterView view in views) {
if (await vmService
for (final FlutterView view in vmService.vm.views) {
if (await view.uiIsolate.vmService
.flutterAlreadyPaintedFirstUsefulFrame(
isolateId: view.uiIsolate.id,
)) {

View file

@ -19,7 +19,6 @@ const String kGetSkSLsMethod = '_flutter.getSkSLs';
const String kSetAssetBundlePathMethod = '_flutter.setAssetBundlePath';
const String kFlushUIThreadTasksMethod = '_flutter.flushUIThreadTasks';
const String kRunInViewMethod = '_flutter.runInView';
const String kListViewsMethod = '_flutter.listViews';
/// The error response code from an unrecoverable compilation failure.
const int kIsolateReloadBarred = 1005;
@ -510,10 +509,10 @@ class VMService implements vm_service.VmService {
// getFromMap creates the Isolate if necessary.
final Isolate isolate = vm.getFromMap(eventIsolate) as Isolate;
event = ServiceObject._fromMap(isolate, eventData) as ServiceEvent;
if (event.kind == vm_service.EventKind.kIsolateExit) {
if (event.kind == ServiceEvent.kIsolateExit) {
vm._isolateCache.remove(isolate.id);
vm._buildIsolateList();
} else if (event.kind == vm_service.EventKind.kIsolateRunnable) {
} else if (event.kind == ServiceEvent.kIsolateRunnable) {
// Force reload once the isolate becomes runnable so that we
// update the root library.
isolate.reload();
@ -533,6 +532,8 @@ class VMService implements vm_service.VmService {
/// Reloads the VM.
Future<void> getVMOld() async => await vm.reload();
Future<void> refreshViews({ bool waitForViews = false }) => vm.refreshViews(waitForViews: waitForViews);
Future<void> close() async {
_delegateService?.dispose();
}
@ -554,16 +555,6 @@ class VMService implements vm_service.VmService {
);
}
@override
Future<vm_service.Isolate> getIsolate(String isolateId) {
return _delegateService.getIsolate(isolateId);
}
@override
Future<vm_service.Success> resume(String isolateId, {String step, int frameIndex}) {
return _delegateService.resume(isolateId, step: step, frameIndex: frameIndex);
}
// To enable a gradual migration to package:vm_service
@override
dynamic noSuchMethod(Invocation invocation) {
@ -653,6 +644,9 @@ abstract class ServiceObject {
case 'Event':
serviceObject = ServiceEvent._empty(owner);
break;
case 'FlutterView':
serviceObject = FlutterView._empty(owner.vm);
break;
case 'Isolate':
serviceObject = Isolate._empty(owner.vm);
break;
@ -796,6 +790,34 @@ class ServiceEvent extends ServiceObject {
String _message;
String get message => _message;
// The possible 'kind' values.
static const String kVMUpdate = 'VMUpdate';
static const String kIsolateStart = 'IsolateStart';
static const String kIsolateRunnable = 'IsolateRunnable';
static const String kIsolateExit = 'IsolateExit';
static const String kIsolateUpdate = 'IsolateUpdate';
static const String kIsolateReload = 'IsolateReload';
static const String kIsolateSpawn = 'IsolateSpawn';
static const String kServiceExtensionAdded = 'ServiceExtensionAdded';
static const String kPauseStart = 'PauseStart';
static const String kPauseExit = 'PauseExit';
static const String kPauseBreakpoint = 'PauseBreakpoint';
static const String kPauseInterrupted = 'PauseInterrupted';
static const String kPauseException = 'PauseException';
static const String kPausePostRequest = 'PausePostRequest';
static const String kNone = 'None';
static const String kResume = 'Resume';
static const String kBreakpointAdded = 'BreakpointAdded';
static const String kBreakpointResolved = 'BreakpointResolved';
static const String kBreakpointRemoved = 'BreakpointRemoved';
static const String kGraph = '_Graph';
static const String kGC = 'GC';
static const String kInspect = 'Inspect';
static const String kDebuggerSettingsUpdate = '_DebuggerSettingsUpdate';
static const String kConnectionClosed = 'ConnectionClosed';
static const String kLogging = '_Logging';
static const String kExtension = 'Extension';
@override
void _update(Map<String, dynamic> map, bool mapIsRef) {
_loaded = true;
@ -820,6 +842,16 @@ class ServiceEvent extends ServiceObject {
_message = utf8.decode(base64.decode(base64Bytes)).trim();
}
}
bool get isPauseEvent {
return kind == kPauseStart ||
kind == kPauseExit ||
kind == kPauseBreakpoint ||
kind == kPauseInterrupted ||
kind == kPauseException ||
kind == kPausePostRequest ||
kind == kNone;
}
}
/// A ServiceObjectOwner is either a [VM] or an [Isolate]. Owners can cache
@ -885,6 +917,9 @@ class VM extends ServiceObjectOwner {
/// The list of live isolates, ordered by isolate start time.
final List<Isolate> isolates = <Isolate>[];
/// The set of live views.
final Map<String, FlutterView> _viewCache = <String, FlutterView>{};
/// The number of bytes allocated (e.g. by malloc) in the native heap.
int _heapAllocatedMemoryUsage;
int get heapAllocatedMemoryUsage => _heapAllocatedMemoryUsage ?? 0;
@ -973,6 +1008,16 @@ class VM extends ServiceObjectOwner {
isolate.updateFromMap(map);
}
return isolate;
case 'FlutterView':
FlutterView view = _viewCache[mapId];
if (view == null) {
// Add new view to the cache.
view = ServiceObject._fromMap(this, map) as FlutterView;
_viewCache[mapId] = view;
} else {
view.updateFromMap(map);
}
return view;
default:
// If we don't have a model object for this service object type, as a
// fallback return a ServiceMap object.
@ -1049,6 +1094,47 @@ class VM extends ServiceObjectOwner {
Future<Map<String, dynamic>> getVMTimeline() {
return invokeRpcRaw('getVMTimeline');
}
Future<void> refreshViews({ bool waitForViews = false }) async {
assert(waitForViews != null);
assert(loaded);
if (!isFlutterEngine) {
return;
}
int failCount = 0;
while (true) {
_viewCache.clear();
// When the future returned by invokeRpc() below returns,
// the _viewCache will have been updated.
// This message updates all the views of every isolate.
await vmService.vm.invokeRpc<ServiceObject>(
'_flutter.listViews', truncateLogs: false);
if (_viewCache.values.isNotEmpty || !waitForViews) {
return;
}
failCount += 1;
if (failCount == 5) { // waited 200ms
globals.printStatus('Flutter is taking longer than expected to report its views. Still trying...');
}
await Future<void>.delayed(const Duration(milliseconds: 50));
await reload();
}
}
Iterable<FlutterView> get views => _viewCache.values;
FlutterView get firstView {
return _viewCache.values.isEmpty ? null : _viewCache.values.first;
}
List<FlutterView> allViewsWithName(String isolateFilter) {
if (_viewCache.values.isEmpty) {
return null;
}
return _viewCache.values.where(
(FlutterView v) => v.uiIsolate.name.contains(isolateFilter)
).toList();
}
}
/// An isolate running inside the VM. Instances of the Isolate class are always
@ -1198,39 +1284,23 @@ class ServiceMap extends ServiceObject implements Map<String, dynamic> {
}
/// Peered to an Android/iOS FlutterView widget on a device.
class FlutterView {
FlutterView({
@required this.id,
@required this.uiIsolate,
});
class FlutterView extends ServiceObject {
FlutterView._empty(ServiceObjectOwner owner) : super._empty(owner);
factory FlutterView.parse(Map<String, Object> json) {
final Map<String, Object> rawIsolate = json['isolate'] as Map<String, Object>;
vm_service.IsolateRef isolate;
if (rawIsolate != null) {
rawIsolate['number'] = rawIsolate['number']?.toString();
isolate = vm_service.IsolateRef.parse(rawIsolate);
}
return FlutterView(
id: json['id'] as String,
uiIsolate: isolate,
);
Isolate _uiIsolate;
Isolate get uiIsolate => _uiIsolate;
@override
void _update(Map<String, dynamic> map, bool mapIsRef) {
_loaded = !mapIsRef;
_upgradeCollection(map, owner);
_uiIsolate = map['isolate'] as Isolate;
}
final vm_service.IsolateRef uiIsolate;
final String id;
bool get hasIsolate => uiIsolate != null;
bool get hasIsolate => _uiIsolate != null;
@override
String toString() => id;
Map<String, Object> toJson() {
return <String, Object>{
'id': id,
'isolate': uiIsolate?.toJson(),
};
}
}
/// Flutter specific VM Service functionality.
@ -1462,15 +1532,13 @@ extension FlutterVmService on vm_service.VmService {
///
/// This method is only supported by certain embedders. This is
/// described by [Device.supportsFlutterExit].
Future<void> flutterExit({
Future<Map<String, dynamic>> flutterExit({
@required String isolateId,
}) {
return invokeFlutterExtensionRpcRaw(
'ext.flutter.exit',
isolateId: isolateId,
).catchError((dynamic error, StackTrace stackTrace) {
// Do nothing on sentinel or exception, the isolate already exited.
}, test: (dynamic error) => error is vm_service.SentinelException || error is vm_service.RPCError);
);
}
/// Return the current platform override for the flutter view running with
@ -1520,37 +1588,4 @@ extension FlutterVmService on vm_service.VmService {
rethrow;
}
}
/// 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>)
];
}
/// Attempt to retrieve the isolate with id [isolateId], or `null` if it has
/// been collected.
Future<vm_service.Isolate> getIsolateOrNull(String isolateId) {
return getIsolate(isolateId)
.catchError((dynamic error, StackTrace stackTrace) {
return null;
}, test: (dynamic error) => error is vm_service.SentinelException);
}
}
/// Whether the event attached to an [Isolate.pauseEvent] should be considered
/// a "pause" event.
bool isPauseEvent(String kind) {
return kind == vm_service.EventKind.kPauseStart ||
kind == vm_service.EventKind.kPauseExit ||
kind == vm_service.EventKind.kPauseBreakpoint ||
kind == vm_service.EventKind.kPauseInterrupted ||
kind == vm_service.EventKind.kPauseException ||
kind == vm_service.EventKind.kPausePostRequest ||
kind == vm_service.EventKind.kNone;
}

View file

@ -7,7 +7,6 @@ import 'dart:async';
import 'package:file/memory.dart';
import 'package:meta/meta.dart';
import 'package:mockito/mockito.dart';
import 'package:platform/platform.dart';
import 'package:process/process.dart';
import 'package:quiver/testing/async.dart';
import 'package:vm_service/vm_service.dart' as vm_service;
@ -35,22 +34,6 @@ import '../../src/context.dart';
import '../../src/fakes.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,
);
void main() {
group('attach', () {
@ -508,7 +491,7 @@ void main() {
}, overrides: <Type, Generator>{
FileSystem: () => testFileSystem,
ProcessManager: () => FakeProcessManager.any(),
}, skip: const LocalPlatform().isWindows); // mDNS does not work on Windows.
});
group('forwarding to given port', () {
const int devicePort = 499;
@ -822,21 +805,11 @@ VMServiceConnector getFakeVmServiceFactory({
version: '',
);
});
when(vmService.getIsolate(any))
.thenAnswer((Invocation invocation) async {
return fakeUnpausedIsolate;
});
when(vmService.callMethod(kListViewsMethod))
.thenAnswer((_) async {
return vm_service.Response.parse(<String, Object>{
'views': <Object>[
<String, Object>{
'id': '1',
'isolate': fakeUnpausedIsolate.toJson()
}
]
});
});
when(vm.refreshViews(waitForViews: anyNamed('waitForViews')))
.thenAnswer((_) => Future<void>.value(null));
when(vm.views)
.thenReturn(<FlutterView>[FlutterViewMock()]);
when(vm.createDevFS(any))
.thenAnswer((_) => Future<Map<String, dynamic>>.value(<String, dynamic>{'uri': '/',}));
@ -886,6 +859,7 @@ class TestHotRunnerFactory extends HotRunnerFactory {
class VMMock extends Mock implements VM {}
class VMServiceMock extends Mock implements VMService {}
class FlutterViewMock extends Mock implements FlutterView {}
class MockProcessManager extends Mock implements ProcessManager {}
class MockProcess extends Mock implements Process {}
class MockHttpClientRequest extends Mock implements HttpClientRequest {}

View file

@ -6,12 +6,6 @@ import 'dart:async';
import 'dart:convert';
import 'package:file/memory.dart';
import 'package:vm_service/vm_service.dart' as vm_service;
import 'package:meta/meta.dart';
import 'package:mockito/mockito.dart';
import 'package:platform/platform.dart';
import 'package:process/process.dart';
import 'package:flutter_tools/src/application_package.dart';
import 'package:flutter_tools/src/artifacts.dart';
import 'package:flutter_tools/src/base/common.dart';
@ -33,27 +27,14 @@ import 'package:flutter_tools/src/fuchsia/tiles_ctl.dart';
import 'package:flutter_tools/src/globals.dart' as globals;
import 'package:flutter_tools/src/project.dart';
import 'package:flutter_tools/src/vmservice.dart';
import 'package:meta/meta.dart';
import 'package:mockito/mockito.dart';
import 'package:platform/platform.dart';
import 'package:process/process.dart';
import '../../src/common.dart';
import '../../src/context.dart';
final vm_service.Isolate fakeIsolate = 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: 'wrong name',
number: '1',
pauseOnExit: false,
runnable: true,
startTime: 0,
);
void main() {
group('fuchsia device', () {
MemoryFileSystem memoryFileSystem;
@ -583,92 +564,71 @@ void main() {
});
group('FuchsiaIsolateDiscoveryProtocol', () {
group(FuchsiaIsolateDiscoveryProtocol, () {
MockPortForwarder portForwarder;
MockVMService vmService;
MockVM vm;
setUp(() {
portForwarder = MockPortForwarder();
vmService = MockVMService();
vm = MockVM();
when(vm.vmService).thenReturn(vmService);
when(vmService.vm).thenReturn(vm);
});
Future<Uri> findUri(List<FlutterView> views, String expectedIsolateName) async {
Future<Uri> findUri(List<MockFlutterView> views, String expectedIsolateName) async {
when(vm.views).thenReturn(views);
for (final MockFlutterView view in views) {
when(view.owner).thenReturn(vm);
}
final MockFuchsiaDevice fuchsiaDevice =
MockFuchsiaDevice('123', portForwarder, false);
MockFuchsiaDevice('123', portForwarder, false);
final FuchsiaIsolateDiscoveryProtocol discoveryProtocol =
FuchsiaIsolateDiscoveryProtocol(
FuchsiaIsolateDiscoveryProtocol(
fuchsiaDevice,
expectedIsolateName,
(Uri uri) async => vmService,
true, // only poll once.
);
when(fuchsiaDevice.servicePorts())
.thenAnswer((Invocation invocation) async => <int>[1]);
when(portForwarder.forward(1))
.thenAnswer((Invocation invocation) async => 2);
when(vmService.getVMOld())
.thenAnswer((Invocation invocation) => Future<void>.value(null));
when(vmService.refreshViews())
.thenAnswer((Invocation invocation) => Future<void>.value(null));
when(vmService.httpAddress).thenReturn(Uri.parse('example'));
when(vmService.callMethod(kListViewsMethod)).thenAnswer((Invocation invocation) async {
return vm_service.Response.parse(<String, Object>{
'views': <Object>[
for (FlutterView view in views)
view.toJson()
],
});
});
return await discoveryProtocol.uri;
}
testUsingContext('can find flutter view with matching isolate name', () async {
const String expectedIsolateName = 'foobar';
final Uri uri = await findUri(<FlutterView>[
// no ui isolate.
FlutterView(id: '1', uiIsolate: null),
// wrong name.
FlutterView(
id: '2',
uiIsolate: vm_service.Isolate.parse(<String, dynamic>{
...fakeIsolate.toJson(),
'name': 'Wrong name',
}),
),
// matching name.
FlutterView(
id: '3',
uiIsolate: vm_service.Isolate.parse(<String, dynamic>{
...fakeIsolate.toJson(),
'name': expectedIsolateName,
}),
),
final Uri uri = await findUri(<MockFlutterView>[
MockFlutterView(null), // no ui isolate.
MockFlutterView(MockIsolate('wrong name')), // wrong name.
MockFlutterView(MockIsolate(expectedIsolateName)), // matching name.
], expectedIsolateName);
expect(
uri.toString(), 'http://${InternetAddress.loopbackIPv4.address}:0/');
});
testUsingContext('can handle flutter view without matching isolate name', () async {
const String expectedIsolateName = 'foobar';
final Future<Uri> uri = findUri(<FlutterView>[
// no ui isolate.
FlutterView(id: '1', uiIsolate: null),
// wrong name.
FlutterView(id: '2', uiIsolate: vm_service.Isolate.parse(<String, Object>{
...fakeIsolate.toJson(),
'name': 'wrong name',
})),
final Future<Uri> uri = findUri(<MockFlutterView>[
MockFlutterView(null), // no ui isolate.
MockFlutterView(MockIsolate('wrong name')), // wrong name.
], expectedIsolateName);
expect(uri, throwsException);
});
testUsingContext('can handle non flutter view', () async {
const String expectedIsolateName = 'foobar';
final Future<Uri> uri = findUri(<FlutterView>[
FlutterView(id: '1', uiIsolate: null), // no ui isolate.
final Future<Uri> uri = findUri(<MockFlutterView>[
MockFlutterView(null), // no ui isolate.
], expectedIsolateName);
expect(uri, throwsException);
});
});
@ -1080,6 +1040,22 @@ class MockPortForwarder extends Mock implements DevicePortForwarder {}
class MockVMService extends Mock implements VMService {}
class MockVM extends Mock implements VM {}
class MockFlutterView extends Mock implements FlutterView {
MockFlutterView(this.uiIsolate);
@override
final Isolate uiIsolate;
}
class MockIsolate extends Mock implements Isolate {
MockIsolate(this.name);
@override
final String name;
}
class FuchsiaDeviceWithFakeDiscovery extends FuchsiaDevice {
FuchsiaDeviceWithFakeDiscovery(String id, {String name}) : super(id, name: name);

View file

@ -4,7 +4,6 @@
import 'dart:async';
import 'package:vm_service/vm_service.dart' as vm_service;
import 'package:flutter_tools/src/artifacts.dart';
import 'package:flutter_tools/src/base/io.dart';
import 'package:flutter_tools/src/build_info.dart';
@ -171,52 +170,6 @@ void main() {
});
testUsingContext('Does hot restarts when all devices support it', () async {
final FakeVmServiceHost fakeVmServiceHost = FakeVmServiceHost(requests: <VmServiceExpectation>[
const FakeVmServiceRequest(
id: '1',
method: kListViewsMethod,
args: null,
jsonResponse: <String, Object>{
'views': <Object>[],
}
),
const FakeVmServiceRequest(
id: '2',
method: kListViewsMethod,
args: null,
jsonResponse: <String, Object>{
'views': <Object>[],
}
),
FakeVmServiceRequest(
id: '3',
method: 'getVM',
args: null,
jsonResponse: vm_service.VM.parse(<String, Object>{}).toJson()
),
FakeVmServiceRequest(
id: '4',
method: 'getVM',
args: null,
jsonResponse: vm_service.VM.parse(<String, Object>{}).toJson()
),
const FakeVmServiceRequest(
id: '5',
method: kListViewsMethod,
args: null,
jsonResponse: <String, Object>{
'views': <Object>[],
}
),
const FakeVmServiceRequest(
id: '6',
method: kListViewsMethod,
args: null,
jsonResponse: <String, Object>{
'views': <Object>[],
}
),
]);
// Setup mocks
final MockDevice mockDevice = MockDevice();
final MockDevice mockHotDevice = MockDevice();
@ -226,12 +179,8 @@ void main() {
when(mockHotDevice.supportsHotRestart).thenReturn(true);
// Trigger a restart.
final List<FlutterDevice> devices = <FlutterDevice>[
FlutterDevice(mockDevice, generator: residentCompiler, buildInfo: BuildInfo.debug)
..vmService = fakeVmServiceHost.vmService
..devFS = mockDevFs,
FlutterDevice(mockHotDevice, generator: residentCompiler, buildInfo: BuildInfo.debug)
..vmService = fakeVmServiceHost.vmService
..devFS = mockDevFs,
FlutterDevice(mockDevice, generator: residentCompiler, buildInfo: BuildInfo.debug)..devFS = mockDevFs,
FlutterDevice(mockHotDevice, generator: residentCompiler, buildInfo: BuildInfo.debug)..devFS = mockDevFs,
];
final HotRunner hotRunner = HotRunner(devices);
final OperationResult result = await hotRunner.restart(fullRestart: true);
@ -262,39 +211,13 @@ void main() {
testUsingContext('hot restart supported', () async {
// Setup mocks
final FakeVmServiceHost fakeVmServiceHost = FakeVmServiceHost(requests: <VmServiceExpectation>[
const FakeVmServiceRequest(
id: '1',
method: kListViewsMethod,
args: null,
jsonResponse: <String, Object>{
'views': <Object>[],
}
),
FakeVmServiceRequest(
id: '2',
method: 'getVM',
args: null,
jsonResponse: vm_service.VM.parse(<String, Object>{}).toJson()
),
const FakeVmServiceRequest(
id: '3',
method: kListViewsMethod,
args: null,
jsonResponse: <String, Object>{
'views': <Object>[],
}
),
]);
final MockDevice mockDevice = MockDevice();
when(mockDevice.supportsHotReload).thenReturn(true);
when(mockDevice.supportsHotRestart).thenReturn(true);
when(mockDevice.targetPlatform).thenAnswer((Invocation _) async => TargetPlatform.tester);
// Trigger hot restart.
final List<FlutterDevice> devices = <FlutterDevice>[
FlutterDevice(mockDevice, generator: residentCompiler, buildInfo: BuildInfo.debug)
..vmService = fakeVmServiceHost.vmService
..devFS = mockDevFs,
FlutterDevice(mockDevice, generator: residentCompiler, buildInfo: BuildInfo.debug)..devFS = mockDevFs,
];
final HotRunner hotRunner = HotRunner(devices);
final OperationResult result = await hotRunner.restart(fullRestart: true);

View file

@ -31,53 +31,16 @@ import '../src/common.dart';
import '../src/context.dart';
import '../src/testbed.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 vm_service.Isolate fakePausedIsolate = vm_service.Isolate(
id: '1',
pauseEvent: vm_service.Event(
kind: vm_service.EventKind.kPauseException,
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,
);
void main() {
final Uri testUri = Uri.parse('foo://bar');
Testbed testbed;
MockFlutterDevice mockFlutterDevice;
MockVMService mockVMService;
MockDevFS mockDevFS;
MockFlutterView mockFlutterView;
ResidentRunner residentRunner;
MockDevice mockDevice;
MockIsolate mockIsolate;
FakeVmServiceHost fakeVmServiceHost;
setUp(() {
@ -98,7 +61,8 @@ void main() {
mockDevice = MockDevice();
mockVMService = MockVMService();
mockDevFS = MockDevFS();
mockFlutterView = MockFlutterView();
mockIsolate = MockIsolate();
// DevFS Mocks
when(mockDevFS.lastCompiled).thenReturn(DateTime(2000));
when(mockDevFS.sources).thenReturn(<Uri>[]);
@ -128,10 +92,10 @@ void main() {
});
when(mockFlutterDevice.devFS).thenReturn(mockDevFS);
when(mockFlutterDevice.views).thenReturn(<FlutterView>[
// NB: still using mock FlutterDevice.
fakeFlutterView,
mockFlutterView,
]);
when(mockFlutterDevice.device).thenReturn(mockDevice);
when(mockFlutterView.uiIsolate).thenReturn(mockIsolate);
when(mockFlutterDevice.stopEchoingDeviceLog()).thenAnswer((Invocation invocation) async { });
when(mockFlutterDevice.observatoryUris).thenAnswer((_) => Stream<Uri>.value(testUri));
when(mockFlutterDevice.connect(
@ -170,6 +134,9 @@ void main() {
final Completer<void> result = Completer<void>.sync();
return result.future;
});
when(mockIsolate.reload()).thenAnswer((Invocation invocation) {
return Future<ServiceObject>.value(null);
});
});
test('ResidentRunner can attach to device successfully', () => testbed.run(() async {
@ -193,32 +160,18 @@ void main() {
test('ResidentRunner can attach to device successfully with --fast-start', () => testbed.run(() async {
fakeVmServiceHost = FakeVmServiceHost(requests: <VmServiceExpectation>[
FakeVmServiceRequest(
id: '1',
method: 'getIsolate',
args: <String, Object>{
'isolateId': fakeUnpausedIsolate.id,
},
jsonResponse: fakeUnpausedIsolate.toJson(),
),
FakeVmServiceRequest(
id: '2',
method: 'getVM',
args: null,
jsonResponse: vm_service.VM.parse(<String, Object>{}).toJson(),
),
const FakeVmServiceRequest(
id: '3',
id: '1',
method: 'streamListen',
args: <String, Object>{
'streamId': 'Isolate',
}
),
FakeVmServiceRequest(
id: '4',
const FakeVmServiceRequest(
id: '2',
method: kRunInViewMethod,
args: <String, Object>{
'viewId': fakeFlutterView.id,
'viewId': null,
'mainScript': 'lib/main.dart.dill',
'assetDirectory': 'build/flutter_assets',
}
@ -319,19 +272,11 @@ void main() {
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
FakeVmServiceRequest(
const FakeVmServiceRequest(
id: '1',
method: 'getIsolate',
args: <String, Object>{
'isolateId': '1',
},
jsonResponse: fakeUnpausedIsolate.toJson(),
),
FakeVmServiceRequest(
id: '2',
method: 'ext.flutter.reassemble',
args: <String, Object>{
'isolateId': fakeUnpausedIsolate.id,
'isolateId': null,
},
),
]);
@ -366,32 +311,18 @@ 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>[
FakeVmServiceRequest(
id: '1',
method: 'getIsolate',
args: <String, Object>{
'isolateId': fakeUnpausedIsolate.id,
},
jsonResponse: fakeUnpausedIsolate.toJson(),
),
FakeVmServiceRequest(
id: '2',
method: 'getVM',
args: null,
jsonResponse: vm_service.VM.parse(<String, Object>{}).toJson(),
),
const FakeVmServiceRequest(
id: '3',
id: '1',
method: 'streamListen',
args: <String, Object>{
'streamId': 'Isolate',
},
),
FakeVmServiceRequest(
id: '4',
const FakeVmServiceRequest(
id: '2',
method: kRunInViewMethod,
args: <String, Object>{
'viewId': fakeFlutterView.id,
'viewId': null,
'mainScript': 'lib/main.dart.dill',
'assetDirectory': 'build/flutter_assets',
},
@ -568,11 +499,11 @@ void main() {
test('ResidentRunner handles writeSkSL returning no data', () => testbed.run(() async {
fakeVmServiceHost = FakeVmServiceHost(requests: <VmServiceExpectation>[
FakeVmServiceRequest(
const FakeVmServiceRequest(
id: '1',
method: kGetSkSLsMethod,
args: <String, Object>{
'viewId': fakeFlutterView.id,
'viewId': null,
},
jsonResponse: <String, Object>{
'SkSLs': <String, Object>{}
@ -586,11 +517,11 @@ void main() {
test('ResidentRunner can write SkSL data to a unique file with engine revision, platform, and device name', () => testbed.run(() async {
fakeVmServiceHost = FakeVmServiceHost(requests: <VmServiceExpectation>[
FakeVmServiceRequest(
const FakeVmServiceRequest(
id: '1',
method: kGetSkSLsMethod,
args: <String, Object>{
'viewId': fakeFlutterView.id,
'viewId': null,
},
jsonResponse: <String, Object>{
'SkSLs': <String, Object>{
@ -618,19 +549,19 @@ void main() {
test('ResidentRunner can take screenshot on debug device', () => testbed.run(() async {
fakeVmServiceHost = FakeVmServiceHost(requests: <VmServiceExpectation>[
FakeVmServiceRequest(
const FakeVmServiceRequest(
id: '1',
method: 'ext.flutter.debugAllowBanner',
args: <String, Object>{
'isolateId': fakeUnpausedIsolate.id,
'isolateId': null,
'enabled': 'false',
},
),
FakeVmServiceRequest(
const FakeVmServiceRequest(
id: '2',
method: 'ext.flutter.debugAllowBanner',
args: <String, Object>{
'isolateId': fakeUnpausedIsolate.id,
'isolateId': null,
'enabled': 'true',
},
)
@ -660,11 +591,11 @@ void main() {
test('ResidentRunner bails taking screenshot on debug device if debugAllowBanner throws RpcError', () => testbed.run(() async {
fakeVmServiceHost = FakeVmServiceHost(requests: <VmServiceExpectation>[
FakeVmServiceRequest(
const FakeVmServiceRequest(
id: '1',
method: 'ext.flutter.debugAllowBanner',
args: <String, Object>{
'isolateId': fakeUnpausedIsolate.id,
'isolateId': null,
'enabled': 'false',
},
// Failed response,
@ -680,19 +611,19 @@ void main() {
test('ResidentRunner bails taking screenshot on debug device if debugAllowBanner during second request', () => testbed.run(() async {
fakeVmServiceHost = FakeVmServiceHost(requests: <VmServiceExpectation>[
FakeVmServiceRequest(
const FakeVmServiceRequest(
id: '1',
method: 'ext.flutter.debugAllowBanner',
args: <String, Object>{
'isolateId': fakeUnpausedIsolate.id,
'isolateId': null,
'enabled': 'false',
},
),
FakeVmServiceRequest(
const FakeVmServiceRequest(
id: '2',
method: 'ext.flutter.debugAllowBanner',
args: <String, Object>{
'isolateId': fakeUnpausedIsolate.id,
'isolateId': null,
'enabled': 'true',
},
// Failed response,
@ -707,19 +638,19 @@ void main() {
test('ResidentRunner bails taking screenshot on debug device if takeScreenshot throws', () => testbed.run(() async {
fakeVmServiceHost = FakeVmServiceHost(requests: <VmServiceExpectation>[
FakeVmServiceRequest(
const FakeVmServiceRequest(
id: '1',
method: 'ext.flutter.debugAllowBanner',
args: <String, Object>{
'isolateId': fakeUnpausedIsolate.id,
'isolateId': null,
'enabled': 'false',
},
),
FakeVmServiceRequest(
const FakeVmServiceRequest(
id: '2',
method: 'ext.flutter.debugAllowBanner',
args: <String, Object>{
'isolateId': fakeUnpausedIsolate.id,
'isolateId': null,
'enabled': 'true',
},
),
@ -763,31 +694,15 @@ void main() {
}));
test('FlutterDevice will not exit a paused isolate', () => testbed.run(() async {
fakeVmServiceHost = FakeVmServiceHost(requests: <VmServiceExpectation>[
FakeVmServiceRequest(
id: '1',
method: '_flutter.listViews',
args: null,
jsonResponse: <String, Object>{
'views': <Object>[
fakeFlutterView.toJson(),
],
},
),
FakeVmServiceRequest(
id: '2',
method: 'getIsolate',
args: <String, Object>{
'isolateId': fakeUnpausedIsolate.id,
},
jsonResponse: fakePausedIsolate.toJson(),
),
]);
fakeVmServiceHost = FakeVmServiceHost(requests: <VmServiceExpectation>[]);
final TestFlutterDevice flutterDevice = TestFlutterDevice(
mockDevice,
<FlutterView>[ fakeFlutterView ],
<FlutterView>[ mockFlutterView ],
);
flutterDevice.vmService = fakeVmServiceHost.vmService;
final MockServiceEvent mockServiceEvent = MockServiceEvent();
when(mockServiceEvent.isPauseEvent).thenReturn(true);
when(mockIsolate.pauseEvent).thenReturn(mockServiceEvent);
when(mockDevice.supportsFlutterExit).thenReturn(true);
await flutterDevice.exitApps();
@ -798,44 +713,26 @@ void main() {
test('FlutterDevice will exit an un-paused isolate', () => testbed.run(() async {
fakeVmServiceHost = FakeVmServiceHost(requests: <VmServiceExpectation>[
FakeVmServiceRequest(
const FakeVmServiceRequest(
id: '1',
method: kListViewsMethod,
args: null,
jsonResponse: <String, Object>{
'views': <Object>[
fakeFlutterView.toJson(),
],
},
),
FakeVmServiceRequest(
id: '2',
method: 'getIsolate',
args: <String, Object>{
'isolateId': fakeUnpausedIsolate.id
},
jsonResponse: fakeUnpausedIsolate.toJson(),
),
FakeVmServiceRequest(
id: '3',
method: 'ext.flutter.exit',
args: <String, Object>{
'isolateId': fakeUnpausedIsolate.id,
'isolateId': null,
},
close: true,
)
]);
final TestFlutterDevice flutterDevice = TestFlutterDevice(
mockDevice,
<FlutterView> [fakeFlutterView ],
<FlutterView> [mockFlutterView],
);
flutterDevice.vmService = fakeVmServiceHost.vmService;
final MockServiceEvent mockServiceEvent = MockServiceEvent();
when(mockServiceEvent.isPauseEvent).thenReturn(false);
when(mockIsolate.pauseEvent).thenReturn(mockServiceEvent);
when(mockDevice.supportsFlutterExit).thenReturn(true);
final Future<void> exitFuture = flutterDevice.exitApps();
await expectLater(exitFuture, completes);
await flutterDevice.exitApps();
expect(fakeVmServiceHost.hasRemainingExpectations, false);
}));
@ -1084,14 +981,17 @@ void main() {
}
class MockFlutterDevice extends Mock implements FlutterDevice {}
class MockFlutterView extends Mock implements FlutterView {}
class MockVMService extends Mock implements VMService {}
class MockDevFS extends Mock implements DevFS {}
class MockIsolate extends Mock implements Isolate {}
class MockDevice extends Mock implements Device {}
class MockDeviceLogReader extends Mock implements DeviceLogReader {}
class MockDevicePortForwarder extends Mock implements DevicePortForwarder {}
class MockUsage extends Mock implements Usage {}
class MockProcessManager extends Mock implements ProcessManager {}
class MockServiceEvent extends Mock implements ServiceEvent {}
class MockVM extends Mock implements VM {}
class TestFlutterDevice extends FlutterDevice {
TestFlutterDevice(Device device, this.views, { Stream<Uri> observatoryUris })
: super(device, buildInfo: BuildInfo.debug) {

View file

@ -91,6 +91,46 @@ final Map<String, Object> listViews = <String, dynamic>{
typedef ServiceCallback = Future<Map<String, dynamic>> Function(Map<String, Object>);
void main() {
testUsingContext('VMService can refreshViews', () async {
final MockVMService mockVmService = MockVMService();
final VMService vmService = VMService(
null,
null,
null,
null,
null,
null,
null,
mockVmService,
Completer<void>(),
const Stream<dynamic>.empty(),
);
verify(mockVmService.registerService('flutterVersion', 'Flutter Tools')).called(1);
when(mockVmService.callServiceExtension('getVM',
args: anyNamed('args'), // Empty
isolateId: null
)).thenAnswer((Invocation invocation) async {
return vm_service.Response.parse(vm);
});
await vmService.getVMOld();
when(mockVmService.callServiceExtension('_flutter.listViews',
args: anyNamed('args'),
isolateId: anyNamed('isolateId')
)).thenAnswer((Invocation invocation) async {
return vm_service.Response.parse(listViews);
});
await vmService.refreshViews(waitForViews: true);
expect(vmService.vm.name, 'vm');
expect(vmService.vm.views.single.id, '_flutterView/0x4a4c1f8');
}, overrides: <Type, Generator>{
Logger: () => BufferLogger.test()
});
testUsingContext('VmService registers reloadSources', () {
Future<void> reloadSources(String isolateId, { bool pause, bool force}) async {}
final MockVMService mockVMService = MockVMService();

View file

@ -97,7 +97,6 @@ void main() {
_project.scheduledBreakpointUri,
_project.scheduledBreakpointLine,
);
await Future<void>.delayed(const Duration(seconds: 2));
await _flutter.hotReload(); // reload triggers code which eventually hits the breakpoint
isolate = await _flutter.waitForPause();
expect(isolate.pauseEvent.kind, equals(EventKind.kPauseBreakpoint));

View file

@ -191,7 +191,7 @@ abstract class FlutterTestDriver {
// ceases to be the case, this code will need changing.
if (_flutterIsolateId == null) {
final VM vm = await _vmService.getVM();
_flutterIsolateId = vm.isolates.single.id;
_flutterIsolateId = vm.isolates.first.id;
}
return _flutterIsolateId;
}

View file

@ -242,11 +242,6 @@ class FakeVmServiceHost {
.having((Map<String, Object> request) => request['id'], 'id', fakeRequest.id)
.having((Map<String, Object> request) => request['params'], 'args', fakeRequest.args)
);
if (fakeRequest.close) {
_vmService.dispose();
expect(_requests, isEmpty);
return;
}
if (fakeRequest.errorCode == null) {
_input.add(json.encode(<String, Object>{
'jsonrpc': '2.0',
@ -303,15 +298,11 @@ class FakeVmServiceRequest implements VmServiceExpectation {
@required this.args,
this.jsonResponse,
this.errorCode,
this.close = false,
});
final String method;
final String id;
/// When true, the vm service is automatically closed.
final bool close;
/// If non-null, the error code for a [vm_service.RPCError] in place of a
/// standard response.
final int errorCode;