Commit d09591bf authored by Yegor's avatar Yegor Committed by GitHub

consistently accept timeout in driver API (#8667)

parent 1ada132e
...@@ -56,6 +56,12 @@ enum TimelineStream { ...@@ -56,6 +56,12 @@ enum TimelineStream {
const List<TimelineStream> _defaultStreams = const <TimelineStream>[TimelineStream.all]; const List<TimelineStream> _defaultStreams = const <TimelineStream>[TimelineStream.all];
/// Default timeout for long-running RPCs.
const Duration _kLongTimeout = const Duration(seconds: 20);
/// Default timeout for short-running RPCs.
const Duration _kShortTimeout = const Duration(seconds: 5);
// See https://github.com/dart-lang/sdk/blob/master/runtime/vm/timeline.cc#L32 // See https://github.com/dart-lang/sdk/blob/master/runtime/vm/timeline.cc#L32
String _timelineStreamsToString(List<TimelineStream> streams) { String _timelineStreamsToString(List<TimelineStream> streams) {
final String contents = streams.map((TimelineStream stream) { final String contents = streams.map((TimelineStream stream) {
...@@ -300,18 +306,18 @@ class FlutterDriver { ...@@ -300,18 +306,18 @@ class FlutterDriver {
} }
/// Checks the status of the Flutter Driver extension. /// Checks the status of the Flutter Driver extension.
Future<Health> checkHealth() async { Future<Health> checkHealth({Duration timeout}) async {
return Health.fromJson(await _sendCommand(new GetHealth())); return Health.fromJson(await _sendCommand(new GetHealth(timeout: timeout)));
} }
/// Returns a dump of the render tree. /// Returns a dump of the render tree.
Future<RenderTree> getRenderTree() async { Future<RenderTree> getRenderTree({Duration timeout}) async {
return RenderTree.fromJson(await _sendCommand(new GetRenderTree())); return RenderTree.fromJson(await _sendCommand(new GetRenderTree(timeout: timeout)));
} }
/// Taps at the center of the widget located by [finder]. /// Taps at the center of the widget located by [finder].
Future<Null> tap(SerializableFinder finder) async { Future<Null> tap(SerializableFinder finder, {Duration timeout}) async {
await _sendCommand(new Tap(finder)); await _sendCommand(new Tap(finder, timeout: timeout));
return null; return null;
} }
...@@ -319,8 +325,8 @@ class FlutterDriver { ...@@ -319,8 +325,8 @@ class FlutterDriver {
/// ///
/// This command invokes the `onChanged` handler of the `Input` widget with /// This command invokes the `onChanged` handler of the `Input` widget with
/// the provided [text]. /// the provided [text].
Future<Null> setInputText(SerializableFinder finder, String text) async { Future<Null> setInputText(SerializableFinder finder, String text, {Duration timeout}) async {
await _sendCommand(new SetInputText(finder, text)); await _sendCommand(new SetInputText(finder, text, timeout: timeout));
return null; return null;
} }
...@@ -328,8 +334,8 @@ class FlutterDriver { ...@@ -328,8 +334,8 @@ class FlutterDriver {
/// ///
/// This command invokes the `onSubmitted` handler of the `Input` widget and /// This command invokes the `onSubmitted` handler of the `Input` widget and
/// the returns the submitted text value. /// the returns the submitted text value.
Future<String> submitInputText(SerializableFinder finder) async { Future<String> submitInputText(SerializableFinder finder, {Duration timeout}) async {
final Map<String, dynamic> json = await _sendCommand(new SubmitInputText(finder)); final Map<String, dynamic> json = await _sendCommand(new SubmitInputText(finder, timeout: timeout));
return json['text']; return json['text'];
} }
...@@ -361,24 +367,24 @@ class FlutterDriver { ...@@ -361,24 +367,24 @@ class FlutterDriver {
/// ///
/// The move events are generated at a given [frequency] in Hz (or events per /// The move events are generated at a given [frequency] in Hz (or events per
/// second). It defaults to 60Hz. /// second). It defaults to 60Hz.
Future<Null> scroll(SerializableFinder finder, double dx, double dy, Duration duration, {int frequency: 60}) async { Future<Null> scroll(SerializableFinder finder, double dx, double dy, Duration duration, { int frequency: 60, Duration timeout }) async {
return await _sendCommand(new Scroll(finder, dx, dy, duration, frequency)).then((Map<String, dynamic> _) => null); return await _sendCommand(new Scroll(finder, dx, dy, duration, frequency, timeout: timeout)).then((Map<String, dynamic> _) => null);
} }
/// Scrolls the Scrollable ancestor of the widget located by [finder] /// Scrolls the Scrollable ancestor of the widget located by [finder]
/// until the widget is completely visible. /// until the widget is completely visible.
Future<Null> scrollIntoView(SerializableFinder finder, { double alignment: 0.0 }) async { Future<Null> scrollIntoView(SerializableFinder finder, { double alignment: 0.0, Duration timeout }) async {
return await _sendCommand(new ScrollIntoView(finder, alignment: alignment)).then((Map<String, dynamic> _) => null); return await _sendCommand(new ScrollIntoView(finder, alignment: alignment, timeout: timeout)).then((Map<String, dynamic> _) => null);
} }
/// Returns the text in the `Text` widget located by [finder]. /// Returns the text in the `Text` widget located by [finder].
Future<String> getText(SerializableFinder finder) async { Future<String> getText(SerializableFinder finder, { Duration timeout }) async {
return GetTextResult.fromJson(await _sendCommand(new GetText(finder))).text; return GetTextResult.fromJson(await _sendCommand(new GetText(finder, timeout: timeout))).text;
} }
/// Take a screenshot. The image will be returned as a PNG. /// Take a screenshot. The image will be returned as a PNG.
Future<List<int>> screenshot() async { Future<List<int>> screenshot({ Duration timeout: _kLongTimeout }) async {
final Map<String, dynamic> result = await _peer.sendRequest('_flutter.screenshot'); final Map<String, dynamic> result = await _peer.sendRequest('_flutter.screenshot').timeout(timeout);
return BASE64.decode(result['screenshot']); return BASE64.decode(result['screenshot']);
} }
...@@ -401,18 +407,18 @@ class FlutterDriver { ...@@ -401,18 +407,18 @@ class FlutterDriver {
/// ] /// ]
/// ///
/// [getFlagList]: https://github.com/dart-lang/sdk/blob/master/runtime/vm/service/service.md#getflaglist /// [getFlagList]: https://github.com/dart-lang/sdk/blob/master/runtime/vm/service/service.md#getflaglist
Future<List<Map<String, dynamic>>> getVmFlags() async { Future<List<Map<String, dynamic>>> getVmFlags({ Duration timeout: _kShortTimeout }) async {
final Map<String, dynamic> result = await _peer.sendRequest('getFlagList'); final Map<String, dynamic> result = await _peer.sendRequest('getFlagList').timeout(timeout);
return result['flags']; return result['flags'];
} }
/// Starts recording performance traces. /// Starts recording performance traces.
Future<Null> startTracing({List<TimelineStream> streams: _defaultStreams}) async { Future<Null> startTracing({ List<TimelineStream> streams: _defaultStreams, Duration timeout: _kShortTimeout }) async {
assert(streams != null && streams.isNotEmpty); assert(streams != null && streams.isNotEmpty);
try { try {
await _peer.sendRequest(_kSetVMTimelineFlagsMethod, <String, String>{ await _peer.sendRequest(_kSetVMTimelineFlagsMethod, <String, String>{
'recordedStreams': _timelineStreamsToString(streams) 'recordedStreams': _timelineStreamsToString(streams)
}); }).timeout(timeout);
return null; return null;
} catch(error, stackTrace) { } catch(error, stackTrace) {
throw new DriverError( throw new DriverError(
...@@ -424,9 +430,11 @@ class FlutterDriver { ...@@ -424,9 +430,11 @@ class FlutterDriver {
} }
/// Stops recording performance traces and downloads the timeline. /// Stops recording performance traces and downloads the timeline.
Future<Timeline> stopTracingAndDownloadTimeline() async { Future<Timeline> stopTracingAndDownloadTimeline({ Duration timeout: _kShortTimeout }) async {
try { try {
await _peer.sendRequest(_kSetVMTimelineFlagsMethod, <String, String>{'recordedStreams': '[]'}); await _peer
.sendRequest(_kSetVMTimelineFlagsMethod, <String, String>{'recordedStreams': '[]'})
.timeout(timeout);
return new Timeline.fromJson(await _peer.sendRequest(_kGetVMTimelineMethod)); return new Timeline.fromJson(await _peer.sendRequest(_kGetVMTimelineMethod));
} catch(error, stackTrace) { } catch(error, stackTrace) {
throw new DriverError( throw new DriverError(
...@@ -469,13 +477,13 @@ class FlutterDriver { ...@@ -469,13 +477,13 @@ class FlutterDriver {
/// With frame sync disabled, its the responsibility of the test author to /// With frame sync disabled, its the responsibility of the test author to
/// ensure that no action is performed while the app is undergoing a /// ensure that no action is performed while the app is undergoing a
/// transition to avoid flakiness. /// transition to avoid flakiness.
Future<T> runUnsynchronized<T>(Future<T> action()) async { Future<T> runUnsynchronized<T>(Future<T> action(), { Duration timeout }) async {
await _sendCommand(new SetFrameSync(false)); await _sendCommand(new SetFrameSync(false, timeout: timeout));
T result; T result;
try { try {
result = await action(); result = await action();
} finally { } finally {
await _sendCommand(new SetFrameSync(true)); await _sendCommand(new SetFrameSync(true, timeout: timeout));
} }
return result; return result;
} }
......
...@@ -207,7 +207,7 @@ class GetText extends CommandWithTarget { ...@@ -207,7 +207,7 @@ class GetText extends CommandWithTarget {
final String kind = 'get_text'; final String kind = 'get_text';
/// [finder] looks for an element that contains a piece of text. /// [finder] looks for an element that contains a piece of text.
GetText(SerializableFinder finder) : super(finder); GetText(SerializableFinder finder, { Duration timeout }) : super(finder, timeout: timeout);
/// Deserializes the command from JSON generated by [serialize]. /// Deserializes the command from JSON generated by [serialize].
GetText.deserialize(Map<String, dynamic> json) : super.deserialize(json); GetText.deserialize(Map<String, dynamic> json) : super.deserialize(json);
......
...@@ -12,7 +12,7 @@ class SetFrameSync extends Command { ...@@ -12,7 +12,7 @@ class SetFrameSync extends Command {
/// Whether frameSync should be enabled or disabled. /// Whether frameSync should be enabled or disabled.
final bool enabled; final bool enabled;
SetFrameSync(this.enabled) : super(); SetFrameSync(this.enabled, { Duration timeout }) : super(timeout: timeout);
/// Deserializes this command from the value generated by [serialize]. /// Deserializes this command from the value generated by [serialize].
SetFrameSync.deserialize(Map<String, String> params) SetFrameSync.deserialize(Map<String, String> params)
......
...@@ -11,7 +11,7 @@ class Tap extends CommandWithTarget { ...@@ -11,7 +11,7 @@ class Tap extends CommandWithTarget {
final String kind = 'tap'; final String kind = 'tap';
/// Creates a tap command to tap on a widget located by [finder]. /// Creates a tap command to tap on a widget located by [finder].
Tap(SerializableFinder finder) : super(finder); Tap(SerializableFinder finder, {Duration timeout}) : super(finder, timeout: timeout);
/// Deserializes this command from JSON generated by [serialize]. /// Deserializes this command from JSON generated by [serialize].
Tap.deserialize(Map<String, String> json) : super.deserialize(json); Tap.deserialize(Map<String, String> json) : super.deserialize(json);
...@@ -44,8 +44,9 @@ class Scroll extends CommandWithTarget { ...@@ -44,8 +44,9 @@ class Scroll extends CommandWithTarget {
this.dx, this.dx,
this.dy, this.dy,
this.duration, this.duration,
this.frequency this.frequency,
) : super(finder); {Duration timeout}
) : super(finder, timeout: timeout);
/// Deserializes this command from JSON generated by [serialize]. /// Deserializes this command from JSON generated by [serialize].
Scroll.deserialize(Map<String, String> json) Scroll.deserialize(Map<String, String> json)
...@@ -95,7 +96,7 @@ class ScrollIntoView extends CommandWithTarget { ...@@ -95,7 +96,7 @@ class ScrollIntoView extends CommandWithTarget {
/// Creates this command given a [finder] used to locate the widget to be /// Creates this command given a [finder] used to locate the widget to be
/// scrolled into view. /// scrolled into view.
ScrollIntoView(SerializableFinder finder, { this.alignment: 0.0 }) : super(finder); ScrollIntoView(SerializableFinder finder, { this.alignment: 0.0, Duration timeout }) : super(finder, timeout: timeout);
/// Deserializes this command from JSON generated by [serialize]. /// Deserializes this command from JSON generated by [serialize].
ScrollIntoView.deserialize(Map<String, String> json) ScrollIntoView.deserialize(Map<String, String> json)
......
...@@ -14,7 +14,7 @@ class SetInputText extends CommandWithTarget { ...@@ -14,7 +14,7 @@ class SetInputText extends CommandWithTarget {
/// ///
/// [finder] identifies the text input widget. [text] is the string that is /// [finder] identifies the text input widget. [text] is the string that is
/// set as the value of the text input. /// set as the value of the text input.
SetInputText(SerializableFinder finder, this.text) : super(finder); SetInputText(SerializableFinder finder, this.text, {Duration timeout}) : super(finder, timeout: timeout);
/// The value of the text input to set. /// The value of the text input to set.
final String text; final String text;
...@@ -52,7 +52,7 @@ class SubmitInputText extends CommandWithTarget { ...@@ -52,7 +52,7 @@ class SubmitInputText extends CommandWithTarget {
final String kind = 'submitInputText'; final String kind = 'submitInputText';
/// Create a command that submits text on input widget identified by [finder]. /// Create a command that submits text on input widget identified by [finder].
SubmitInputText(SerializableFinder finder) : super(finder); SubmitInputText(SerializableFinder finder, {Duration timeout}) : super(finder, timeout: timeout);
/// Deserializes this command from JSON generated by [serialize]. /// Deserializes this command from JSON generated by [serialize].
SubmitInputText.deserialize(Map<String, String> json) SubmitInputText.deserialize(Map<String, String> json)
......
...@@ -13,6 +13,10 @@ import 'package:mockito/mockito_no_mirrors.dart'; ...@@ -13,6 +13,10 @@ import 'package:mockito/mockito_no_mirrors.dart';
import 'package:test/test.dart'; import 'package:test/test.dart';
import 'package:vm_service_client/vm_service_client.dart'; import 'package:vm_service_client/vm_service_client.dart';
/// Magical timeout value that's different from the default.
const Duration _kTestTimeout = const Duration(milliseconds: 1234);
const String _kSerializedTestTimeout = '1234';
void main() { void main() {
group('FlutterDriver.connect', () { group('FlutterDriver.connect', () {
List<LogRecord> log; List<LogRecord> log;
...@@ -127,14 +131,14 @@ void main() { ...@@ -127,14 +131,14 @@ void main() {
when(mockIsolate.invokeExtension(any, any)).thenAnswer((Invocation i) { when(mockIsolate.invokeExtension(any, any)).thenAnswer((Invocation i) {
expect(i.positionalArguments[1], <String, String>{ expect(i.positionalArguments[1], <String, String>{
'command': 'tap', 'command': 'tap',
'timeout': '5000', 'timeout': _kSerializedTestTimeout,
'finderType': 'ByValueKey', 'finderType': 'ByValueKey',
'keyValueString': 'foo', 'keyValueString': 'foo',
'keyValueType': 'String' 'keyValueType': 'String'
}); });
return makeMockResponse(<String, dynamic>{}); return makeMockResponse(<String, dynamic>{});
}); });
await driver.tap(find.byValueKey('foo')); await driver.tap(find.byValueKey('foo'), timeout: _kTestTimeout);
}); });
}); });
...@@ -147,13 +151,13 @@ void main() { ...@@ -147,13 +151,13 @@ void main() {
when(mockIsolate.invokeExtension(any, any)).thenAnswer((Invocation i) { when(mockIsolate.invokeExtension(any, any)).thenAnswer((Invocation i) {
expect(i.positionalArguments[1], <String, dynamic>{ expect(i.positionalArguments[1], <String, dynamic>{
'command': 'tap', 'command': 'tap',
'timeout': '5000', 'timeout': _kSerializedTestTimeout,
'finderType': 'ByText', 'finderType': 'ByText',
'text': 'foo', 'text': 'foo',
}); });
return makeMockResponse(<String, dynamic>{}); return makeMockResponse(<String, dynamic>{});
}); });
await driver.tap(find.text('foo')); await driver.tap(find.text('foo'), timeout: _kTestTimeout);
}); });
}); });
...@@ -166,7 +170,7 @@ void main() { ...@@ -166,7 +170,7 @@ void main() {
when(mockIsolate.invokeExtension(any, any)).thenAnswer((Invocation i) { when(mockIsolate.invokeExtension(any, any)).thenAnswer((Invocation i) {
expect(i.positionalArguments[1], <String, dynamic>{ expect(i.positionalArguments[1], <String, dynamic>{
'command': 'get_text', 'command': 'get_text',
'timeout': '5000', 'timeout': _kSerializedTestTimeout,
'finderType': 'ByValueKey', 'finderType': 'ByValueKey',
'keyValueString': '123', 'keyValueString': '123',
'keyValueType': 'int' 'keyValueType': 'int'
...@@ -175,7 +179,7 @@ void main() { ...@@ -175,7 +179,7 @@ void main() {
'text': 'hello' 'text': 'hello'
}); });
}); });
final String result = await driver.getText(find.byValueKey(123)); final String result = await driver.getText(find.byValueKey(123), timeout: _kTestTimeout);
expect(result, 'hello'); expect(result, 'hello');
}); });
}); });
...@@ -191,11 +195,11 @@ void main() { ...@@ -191,11 +195,11 @@ void main() {
'command': 'waitFor', 'command': 'waitFor',
'finderType': 'ByTooltipMessage', 'finderType': 'ByTooltipMessage',
'text': 'foo', 'text': 'foo',
'timeout': '1000', 'timeout': _kSerializedTestTimeout,
}); });
return makeMockResponse(<String, dynamic>{}); return makeMockResponse(<String, dynamic>{});
}); });
await driver.waitFor(find.byTooltip('foo'), timeout: const Duration(seconds: 1)); await driver.waitFor(find.byTooltip('foo'), timeout: _kTestTimeout);
}); });
}); });
...@@ -204,11 +208,11 @@ void main() { ...@@ -204,11 +208,11 @@ void main() {
when(mockIsolate.invokeExtension(any, any)).thenAnswer((Invocation i) { when(mockIsolate.invokeExtension(any, any)).thenAnswer((Invocation i) {
expect(i.positionalArguments[1], <String, dynamic>{ expect(i.positionalArguments[1], <String, dynamic>{
'command': 'waitUntilNoTransientCallbacks', 'command': 'waitUntilNoTransientCallbacks',
'timeout': '1000', 'timeout': _kSerializedTestTimeout,
}); });
return makeMockResponse(<String, dynamic>{}); return makeMockResponse(<String, dynamic>{});
}); });
await driver.waitUntilNoTransientCallbacks(timeout: const Duration(seconds: 1)); await driver.waitUntilNoTransientCallbacks(timeout: _kTestTimeout);
}); });
}); });
......
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