Unverified Commit 5fa5701d authored by Brian Eaton's avatar Brian Eaton Committed by GitHub

Make sure all isolates start during flutter driver tests. (#61841)

parent d1411a16
......@@ -127,27 +127,6 @@ class VMServiceFlutterDriver extends FlutterDriver {
driver._dartVmReconnectUrl = dartVmServiceUrl;
// Attempts to resume the isolate, but does not crash if it fails because
// the isolate is already resumed. There could be a race with other tools,
// such as a debugger, any of which could have resumed the isolate.
Future<dynamic> resumeLeniently() {
_log('Attempting to resume isolate');
return isolate.resume().catchError((dynamic e) {
const int vmMustBePausedCode = 101;
if (e is rpc.RpcException && e.code == vmMustBePausedCode) {
// No biggie; something else must have resumed the isolate
_log(
'Attempted to resume an already resumed isolate. This may happen '
'when we lose a race with another tool (usually a debugger) that '
'is connected to the same isolate.'
);
} else {
// Failed to resume due to another reason. Fail hard.
throw e;
}
});
}
/// Waits for a signal from the VM service that the extension is registered.
///
/// Looks at the list of loaded extensions for the current [isolateRef], as
......@@ -195,11 +174,18 @@ class VMServiceFlutterDriver extends FlutterDriver {
});
}
// The Dart VM may be running with --pause-isolates-on-start.
// Set a listener to unpause new isolates as they are ready to run,
// otherwise they'll hang indefinitely.
client.onIsolateRunnable.listen((VMIsolateRef isolateRef) async {
_resumeLeniently(await isolateRef.load());
});
// Attempt to resume isolate if it was paused
if (isolate.pauseEvent is VMPauseStartEvent) {
_log('Isolate is paused at start.');
await resumeLeniently();
await _resumeLeniently(isolate);
} else if (isolate.pauseEvent is VMPauseExitEvent ||
isolate.pauseEvent is VMPauseBreakpointEvent ||
isolate.pauseEvent is VMPauseExceptionEvent ||
......@@ -207,7 +193,7 @@ class VMServiceFlutterDriver extends FlutterDriver {
// If the isolate is paused for any other reason, assume the extension is
// already there.
_log('Isolate is paused mid-flight.');
await resumeLeniently();
await _resumeLeniently(isolate);
} else if (isolate.pauseEvent is VMResumeEvent) {
_log('Isolate is not paused. Assuming application is ready.');
} else {
......@@ -240,6 +226,27 @@ class VMServiceFlutterDriver extends FlutterDriver {
return driver;
}
/// Attempts to resume the isolate, but does not crash if it fails because
/// the isolate is already resumed. There could be a race with other tools,
/// such as a debugger, any of which could have resumed the isolate.
static Future<dynamic> _resumeLeniently(VMIsolate isolate) {
_log('Attempting to resume isolate');
return isolate.resume().catchError((dynamic e) {
const int vmMustBePausedCode = 101;
if (e is rpc.RpcException && e.code == vmMustBePausedCode) {
// No biggie; something else must have resumed the isolate
_log(
'Attempted to resume an already resumed isolate. This may happen '
'when we lose a race with another tool (usually a debugger) that '
'is connected to the same isolate.'
);
} else {
// Failed to resume due to another reason. Fail hard.
throw e;
}
});
}
static int _nextDriverId = 0;
static const String _flutterExtensionMethodName = 'ext.flutter.driver';
......
......@@ -35,6 +35,7 @@ void main() {
MockVM mockVM;
MockIsolate mockIsolate;
MockPeer mockPeer;
MockIsolate otherIsolate;
void expectLogContains(String message) {
expect(log, anyElement(contains(message)));
......@@ -45,8 +46,12 @@ void main() {
mockClient = MockVMServiceClient();
mockVM = MockVM();
mockIsolate = MockIsolate();
otherIsolate = MockIsolate();
mockPeer = MockPeer();
when(mockClient.getVM()).thenAnswer((_) => Future<MockVM>.value(mockVM));
when(mockClient.onIsolateRunnable).thenAnswer((Invocation invocation) {
return Stream<VMIsolateRef>.fromIterable(<VMIsolateRef>[otherIsolate]);
});
when(mockVM.isolates).thenReturn(<VMRunnableIsolate>[mockIsolate]);
when(mockIsolate.loadRunnable()).thenAnswer((_) => Future<MockIsolate>.value(mockIsolate));
when(mockIsolate.extensionRpcs).thenReturn(<String>[]);
......@@ -60,6 +65,10 @@ void main() {
VMServiceClientConnection(mockClient, mockPeer)
);
};
when(otherIsolate.load()).thenAnswer((_) => Future<MockIsolate>.value(otherIsolate));
when(otherIsolate.resume()).thenAnswer((Invocation invocation) {
return Future<dynamic>.value(null);
});
});
tearDown(() async {
......@@ -77,15 +86,20 @@ void main() {
connectionLog.add('resume');
return Future<dynamic>.value(null);
});
when(otherIsolate.pauseEvent).thenReturn(MockVMPauseStartEvent());
when(mockIsolate.onExtensionAdded).thenAnswer((Invocation invocation) {
connectionLog.add('onExtensionAdded');
return Stream<String>.fromIterable(<String>['ext.flutter.driver']);
});
when(otherIsolate.resume()).thenAnswer((Invocation invocation) {
connectionLog.add('other-resume');
return Future<dynamic>.value(null);
});
final FlutterDriver driver = await FlutterDriver.connect(dartVmServiceUrl: '');
expect(driver, isNotNull);
expectLogContains('Isolate is paused at start');
expect(connectionLog, <String>['resume', 'streamListen', 'onExtensionAdded']);
expect(connectionLog, <String>['resume', 'streamListen', 'other-resume', 'onExtensionAdded']);
});
test('connects to isolate paused mid-flight', () async {
......
Markdown is supported
0% or
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment