Make sure all isolates start during flutter driver tests. (#61841)
This commit is contained in:
parent
d1411a1626
commit
5fa5701d72
@ -127,27 +127,6 @@ class VMServiceFlutterDriver extends FlutterDriver {
|
|||||||
|
|
||||||
driver._dartVmReconnectUrl = dartVmServiceUrl;
|
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.
|
/// 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
|
/// 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
|
// Attempt to resume isolate if it was paused
|
||||||
if (isolate.pauseEvent is VMPauseStartEvent) {
|
if (isolate.pauseEvent is VMPauseStartEvent) {
|
||||||
_log('Isolate is paused at start.');
|
_log('Isolate is paused at start.');
|
||||||
|
|
||||||
await resumeLeniently();
|
await _resumeLeniently(isolate);
|
||||||
} else if (isolate.pauseEvent is VMPauseExitEvent ||
|
} else if (isolate.pauseEvent is VMPauseExitEvent ||
|
||||||
isolate.pauseEvent is VMPauseBreakpointEvent ||
|
isolate.pauseEvent is VMPauseBreakpointEvent ||
|
||||||
isolate.pauseEvent is VMPauseExceptionEvent ||
|
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
|
// If the isolate is paused for any other reason, assume the extension is
|
||||||
// already there.
|
// already there.
|
||||||
_log('Isolate is paused mid-flight.');
|
_log('Isolate is paused mid-flight.');
|
||||||
await resumeLeniently();
|
await _resumeLeniently(isolate);
|
||||||
} else if (isolate.pauseEvent is VMResumeEvent) {
|
} else if (isolate.pauseEvent is VMResumeEvent) {
|
||||||
_log('Isolate is not paused. Assuming application is ready.');
|
_log('Isolate is not paused. Assuming application is ready.');
|
||||||
} else {
|
} else {
|
||||||
@ -240,6 +226,27 @@ class VMServiceFlutterDriver extends FlutterDriver {
|
|||||||
return driver;
|
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 int _nextDriverId = 0;
|
||||||
|
|
||||||
static const String _flutterExtensionMethodName = 'ext.flutter.driver';
|
static const String _flutterExtensionMethodName = 'ext.flutter.driver';
|
||||||
|
@ -35,6 +35,7 @@ void main() {
|
|||||||
MockVM mockVM;
|
MockVM mockVM;
|
||||||
MockIsolate mockIsolate;
|
MockIsolate mockIsolate;
|
||||||
MockPeer mockPeer;
|
MockPeer mockPeer;
|
||||||
|
MockIsolate otherIsolate;
|
||||||
|
|
||||||
void expectLogContains(String message) {
|
void expectLogContains(String message) {
|
||||||
expect(log, anyElement(contains(message)));
|
expect(log, anyElement(contains(message)));
|
||||||
@ -45,8 +46,12 @@ void main() {
|
|||||||
mockClient = MockVMServiceClient();
|
mockClient = MockVMServiceClient();
|
||||||
mockVM = MockVM();
|
mockVM = MockVM();
|
||||||
mockIsolate = MockIsolate();
|
mockIsolate = MockIsolate();
|
||||||
|
otherIsolate = MockIsolate();
|
||||||
mockPeer = MockPeer();
|
mockPeer = MockPeer();
|
||||||
when(mockClient.getVM()).thenAnswer((_) => Future<MockVM>.value(mockVM));
|
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(mockVM.isolates).thenReturn(<VMRunnableIsolate>[mockIsolate]);
|
||||||
when(mockIsolate.loadRunnable()).thenAnswer((_) => Future<MockIsolate>.value(mockIsolate));
|
when(mockIsolate.loadRunnable()).thenAnswer((_) => Future<MockIsolate>.value(mockIsolate));
|
||||||
when(mockIsolate.extensionRpcs).thenReturn(<String>[]);
|
when(mockIsolate.extensionRpcs).thenReturn(<String>[]);
|
||||||
@ -60,6 +65,10 @@ void main() {
|
|||||||
VMServiceClientConnection(mockClient, mockPeer)
|
VMServiceClientConnection(mockClient, mockPeer)
|
||||||
);
|
);
|
||||||
};
|
};
|
||||||
|
when(otherIsolate.load()).thenAnswer((_) => Future<MockIsolate>.value(otherIsolate));
|
||||||
|
when(otherIsolate.resume()).thenAnswer((Invocation invocation) {
|
||||||
|
return Future<dynamic>.value(null);
|
||||||
|
});
|
||||||
});
|
});
|
||||||
|
|
||||||
tearDown(() async {
|
tearDown(() async {
|
||||||
@ -77,15 +86,20 @@ void main() {
|
|||||||
connectionLog.add('resume');
|
connectionLog.add('resume');
|
||||||
return Future<dynamic>.value(null);
|
return Future<dynamic>.value(null);
|
||||||
});
|
});
|
||||||
|
when(otherIsolate.pauseEvent).thenReturn(MockVMPauseStartEvent());
|
||||||
when(mockIsolate.onExtensionAdded).thenAnswer((Invocation invocation) {
|
when(mockIsolate.onExtensionAdded).thenAnswer((Invocation invocation) {
|
||||||
connectionLog.add('onExtensionAdded');
|
connectionLog.add('onExtensionAdded');
|
||||||
return Stream<String>.fromIterable(<String>['ext.flutter.driver']);
|
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: '');
|
final FlutterDriver driver = await FlutterDriver.connect(dartVmServiceUrl: '');
|
||||||
expect(driver, isNotNull);
|
expect(driver, isNotNull);
|
||||||
expectLogContains('Isolate is paused at start');
|
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 {
|
test('connects to isolate paused mid-flight', () async {
|
||||||
|
Loading…
x
Reference in New Issue
Block a user