mirror of
https://github.com/flutter/flutter
synced 2024-08-27 03:50:33 +00:00
Make Flutter Driver actively wait for runnable isolate (#113969)
* Test the case when main Isolate is in `None` state for long time * Wait for isolate to become runnable * Handle `PausePostRequest` as a normal "paused" event * Use `-= 1` instead of `--`
This commit is contained in:
parent
4fdaf7ae25
commit
4301731eb2
|
@ -100,6 +100,19 @@ class VMServiceFlutterDriver extends FlutterDriver {
|
|||
}
|
||||
}
|
||||
|
||||
// Refreshes the isolate state periodically until the isolate reports as
|
||||
// being runnable.
|
||||
Future<vms.Isolate> waitForIsolateToBeRunnable(vms.IsolateRef ref) async {
|
||||
while (true) {
|
||||
final vms.Isolate isolate = await client.getIsolate(ref.id!);
|
||||
if (isolate.pauseEvent!.kind == vms.EventKind.kNone) {
|
||||
await Future<void>.delayed(_kPauseBetweenIsolateRefresh);
|
||||
} else {
|
||||
return isolate;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
final vms.IsolateRef isolateRef = (await _warnIfSlow<vms.IsolateRef?>(
|
||||
future: waitForRootIsolate(),
|
||||
timeout: kUnusuallyLongTimeout,
|
||||
|
@ -108,11 +121,13 @@ class VMServiceFlutterDriver extends FlutterDriver {
|
|||
: 'Isolate $isolateNumber is taking an unusually long time to start.',
|
||||
))!;
|
||||
_log('Isolate found with number: ${isolateRef.number}');
|
||||
vms.Isolate isolate = await client.getIsolate(isolateRef.id!);
|
||||
|
||||
if (isolate.pauseEvent!.kind == vms.EventKind.kNone) {
|
||||
isolate = await client.getIsolate(isolateRef.id!);
|
||||
}
|
||||
final vms.Isolate isolate = await _warnIfSlow<vms.Isolate>(
|
||||
future: waitForIsolateToBeRunnable(isolateRef),
|
||||
timeout: kUnusuallyLongTimeout,
|
||||
message: 'The isolate ${isolateRef.number} is taking unusually long time '
|
||||
'to initialize. It still reports ${vms.EventKind.kNone} as pause '
|
||||
'event which is incorrect.',
|
||||
);
|
||||
|
||||
final VMServiceFlutterDriver driver = VMServiceFlutterDriver.connectedTo(
|
||||
client,
|
||||
|
@ -201,7 +216,8 @@ class VMServiceFlutterDriver extends FlutterDriver {
|
|||
} else if (isolate.pauseEvent!.kind == vms.EventKind.kPauseExit ||
|
||||
isolate.pauseEvent!.kind == vms.EventKind.kPauseBreakpoint ||
|
||||
isolate.pauseEvent!.kind == vms.EventKind.kPauseException ||
|
||||
isolate.pauseEvent!.kind == vms.EventKind.kPauseInterrupted) {
|
||||
isolate.pauseEvent!.kind == vms.EventKind.kPauseInterrupted ||
|
||||
isolate.pauseEvent!.kind == vms.EventKind.kPausePostRequest) {
|
||||
// If the isolate is paused for any other reason, assume the extension is
|
||||
// already there.
|
||||
_log('Isolate is paused mid-flight.');
|
||||
|
@ -583,6 +599,9 @@ Future<vms.VmService> _waitAndConnect(String url, Map<String, dynamic>? headers)
|
|||
/// the VM service.
|
||||
const Duration _kPauseBetweenReconnectAttempts = Duration(seconds: 1);
|
||||
|
||||
/// The amount of time we wait prior to refreshing the isolate state.
|
||||
const Duration _kPauseBetweenIsolateRefresh = Duration(milliseconds: 100);
|
||||
|
||||
// See `timeline_streams` in
|
||||
// https://github.com/dart-lang/sdk/blob/main/runtime/vm/timeline.cc
|
||||
List<String> _timelineStreamsToString(List<TimelineStream> streams) {
|
||||
|
|
|
@ -189,6 +189,33 @@ void main() {
|
|||
);
|
||||
});
|
||||
|
||||
test('Refreshes isolate if it is not started for long time', () async {
|
||||
fakeIsolate.pauseEvent = vms.Event(kind: vms.EventKind.kNone, timestamp: 0);
|
||||
fakeClient.onGetIsolate = changeIsolateEventAfter(
|
||||
5,
|
||||
vms.Event(kind: vms.EventKind.kPauseStart, timestamp: 1),
|
||||
);
|
||||
|
||||
final FlutterDriver driver = await FlutterDriver.connect(dartVmServiceUrl: '');
|
||||
expect(driver, isNotNull);
|
||||
expect(
|
||||
fakeClient.connectionLog,
|
||||
<String>[
|
||||
'getIsolate',
|
||||
'getIsolate',
|
||||
'getIsolate',
|
||||
'getIsolate',
|
||||
'getIsolate',
|
||||
'setFlag pause_isolates_on_start false',
|
||||
'resume',
|
||||
'streamListen Isolate',
|
||||
'getIsolate',
|
||||
'onIsolateEvent',
|
||||
'streamCancel Isolate',
|
||||
],
|
||||
);
|
||||
});
|
||||
|
||||
test('Connects to isolate number', () async {
|
||||
fakeIsolate.pauseEvent = vms.Event(kind: vms.EventKind.kPauseStart, timestamp: 0);
|
||||
final FlutterDriver driver = await FlutterDriver.connect(dartVmServiceUrl: '', isolateNumber: int.parse(fakeIsolate.number!));
|
||||
|
@ -246,6 +273,14 @@ void main() {
|
|||
expectLogContains('Isolate is paused mid-flight');
|
||||
});
|
||||
|
||||
test('connects to isolate paused mid-flight after request', () async {
|
||||
fakeIsolate.pauseEvent = vms.Event(kind: vms.EventKind.kPausePostRequest, timestamp: 0);
|
||||
|
||||
final FlutterDriver driver = await FlutterDriver.connect(dartVmServiceUrl: '');
|
||||
expect(driver, isNotNull);
|
||||
expectLogContains('Isolate is paused mid-flight');
|
||||
});
|
||||
|
||||
// This test simulates a situation when we believe that the isolate is
|
||||
// currently paused, but something else (e.g. a debugger) resumes it before
|
||||
// we do. There's no need to fail as we should be able to drive the app
|
||||
|
@ -1055,6 +1090,15 @@ vms.Response? makeFakeResponse(
|
|||
});
|
||||
}
|
||||
|
||||
void Function(vms.Isolate) changeIsolateEventAfter(int gets, vms.Event nextEvent) {
|
||||
return (vms.Isolate i) {
|
||||
gets -= 1;
|
||||
if (gets == 0) {
|
||||
i.pauseEvent = nextEvent;
|
||||
}
|
||||
};
|
||||
}
|
||||
|
||||
class FakeFlutterWebConnection extends Fake implements FlutterWebConnection {
|
||||
@override
|
||||
bool supportsTimelineAction = false;
|
||||
|
@ -1082,6 +1126,7 @@ class FakeVmService extends Fake implements vms.VmService {
|
|||
FakeVM? vm;
|
||||
bool failOnSetFlag = false;
|
||||
bool failOnResumeWith101 = false;
|
||||
void Function(vms.Isolate)? onGetIsolate;
|
||||
|
||||
final List<String> connectionLog = <String>[];
|
||||
|
||||
|
@ -1092,6 +1137,7 @@ class FakeVmService extends Fake implements vms.VmService {
|
|||
Future<vms.Isolate> getIsolate(String isolateId) async {
|
||||
connectionLog.add('getIsolate');
|
||||
if (isolateId == vm!.isolate!.id) {
|
||||
onGetIsolate?.call(vm!.isolate!);
|
||||
return vm!.isolate!;
|
||||
}
|
||||
throw UnimplementedError('getIsolate called with unrecognized $isolateId');
|
||||
|
|
Loading…
Reference in a new issue