Skip to content
This repository was archived by the owner on Feb 22, 2023. It is now read-only.

Commit 29a76f6

Browse files
committed
add support to timeline
1 parent 89794a6 commit 29a76f6

File tree

4 files changed

+128
-12
lines changed

4 files changed

+128
-12
lines changed

packages/integration_test/example/test_driver/example_integration_io.dart

Lines changed: 15 additions & 12 deletions
Original file line numberDiff line numberDiff line change
@@ -13,22 +13,25 @@ import 'package:integration_test/integration_test.dart';
1313
import 'package:integration_test_example/main.dart' as app;
1414

1515
void main() {
16-
IntegrationTestWidgetsFlutterBinding.ensureInitialized();
16+
final IntegrationTestWidgetsFlutterBinding binding =
17+
IntegrationTestWidgetsFlutterBinding.ensureInitialized() as IntegrationTestWidgetsFlutterBinding;
1718
testWidgets('verify text', (WidgetTester tester) async {
1819
// Build our app and trigger a frame.
1920
app.main();
2021

21-
// Trigger a frame.
22-
await tester.pumpAndSettle();
22+
await binding.traceAction(() async {
23+
// Trigger a frame.
24+
await tester.pumpAndSettle();
2325

24-
// Verify that platform version is retrieved.
25-
expect(
26-
find.byWidgetPredicate(
27-
(Widget widget) =>
28-
widget is Text &&
29-
widget.data.startsWith('Platform: ${Platform.operatingSystem}'),
30-
),
31-
findsOneWidget,
32-
);
26+
// Verify that platform version is retrieved.
27+
expect(
28+
find.byWidgetPredicate(
29+
(Widget widget) =>
30+
widget is Text &&
31+
widget.data.startsWith('Platform: ${Platform.operatingSystem}'),
32+
),
33+
findsOneWidget,
34+
);
35+
});
3336
});
3437
}

packages/integration_test/lib/integration_test.dart

Lines changed: 77 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -3,12 +3,15 @@
33
// found in the LICENSE file.
44

55
import 'dart:async';
6+
import 'dart:developer' as developer;
67

78
import 'package:flutter/rendering.dart';
89
import 'package:flutter_test/flutter_test.dart';
910
import 'package:flutter/foundation.dart';
1011
import 'package:flutter/services.dart';
1112
import 'package:flutter/widgets.dart';
13+
import 'package:vm_service/vm_service.dart' as vm;
14+
import 'package:vm_service/vm_service_io.dart' as vm_io;
1215

1316
import 'common.dart';
1417
import '_extension_io.dart' if (dart.library.html) '_extension_web.dart';
@@ -188,4 +191,78 @@ class IntegrationTestWidgetsFlutterBinding
188191
);
189192
results[description] ??= 'success';
190193
}
194+
195+
vm.VmService _vmService;
196+
197+
/// Initialize the [vm.VmService] settings for the timeline.
198+
@visibleForTesting
199+
Future<void> enableTimeline({
200+
List<String> streams = const <String>['all'],
201+
@visibleForTesting vm.VmService vmService,
202+
}) async {
203+
assert(streams != null);
204+
assert(streams.isNotEmpty);
205+
if (vmService != null) {
206+
_vmService = vmService;
207+
}
208+
if (_vmService == null) {
209+
final developer.ServiceProtocolInfo info = await developer.Service.getInfo();
210+
assert(info.serverUri != null);
211+
_vmService = await vm_io.vmServiceConnectUri(
212+
'ws://localhost:${info.serverUri.port}${info.serverUri.path}ws',
213+
);
214+
}
215+
await _vmService.setVMTimelineFlags(streams);
216+
}
217+
218+
/// Runs [action] and outputs a [vm.Timeline] trace for it.
219+
///
220+
/// Waits for the `Future` returned by [action] to complete prior to stopping
221+
/// the trace.
222+
///
223+
/// `streams` limits the recorded timeline event streams to only the ones
224+
/// listed. By default, all streams are recorded.
225+
/// See `timeline_streams` in
226+
/// https://github.com/dart-lang/sdk/blob/master/runtime/vm/timeline.cc
227+
///
228+
/// If [retainPriorEvents] is true, retains events recorded prior to calling
229+
/// [action]. Otherwise, prior events are cleared before calling [action]. By
230+
/// default, prior events are cleared.
231+
Future<vm.Timeline> traceTimeline(
232+
Future<dynamic> action(), {
233+
List<String> streams = const <String>['all'],
234+
bool retainPriorEvents = false,
235+
}) async {
236+
await enableTimeline(streams: streams);
237+
if (retainPriorEvents) {
238+
await action();
239+
return await _vmService.getVMTimeline();
240+
}
241+
242+
await _vmService.clearVMTimeline();
243+
final vm.Timestamp startTime = await _vmService.getVMTimelineMicros();
244+
await action();
245+
final vm.Timestamp endTime = await _vmService.getVMTimelineMicros();
246+
return await _vmService.getVMTimeline(
247+
timeOriginMicros: startTime.timestamp,
248+
timeExtentMicros: endTime.timestamp,
249+
);
250+
}
251+
252+
/// This is a convience wrap of [traceTimeline] and send the result back to
253+
/// the host.
254+
Future<void> traceAction(
255+
Future<dynamic> action(), {
256+
List<String> streams = const <String>['all'],
257+
bool retainPriorEvents = false,
258+
String reportKey = 'timeline',
259+
}) async {
260+
vm.Timeline timeline = await traceTimeline(
261+
action,
262+
streams: streams,
263+
retainPriorEvents: retainPriorEvents,
264+
);
265+
reportData ??= <String, dynamic>{};
266+
reportData[reportKey] = timeline.toJson();
267+
}
191268
}

packages/integration_test/pubspec.yaml

Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -15,9 +15,11 @@ dependencies:
1515
flutter_test:
1616
sdk: flutter
1717
path: ^1.6.4
18+
vm_service: ^4.2.0
1819

1920
dev_dependencies:
2021
pedantic: ^1.8.0
22+
mockito: ^4.1.1
2123

2224
flutter:
2325
plugin:

packages/integration_test/test/binding_test.dart

Lines changed: 34 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -1,8 +1,18 @@
1+
import 'dart:convert';
2+
13
import 'package:flutter/material.dart';
24

35
import 'package:integration_test/integration_test.dart';
46
import 'package:integration_test/common.dart';
57
import 'package:flutter_test/flutter_test.dart';
8+
import 'package:mockito/mockito.dart';
9+
import 'package:vm_service/vm_service.dart' as vm;
10+
11+
vm.Timeline _ktimelines = vm.Timeline(
12+
traceEvents: <vm.TimelineEvent>[],
13+
timeOriginMicros: 100,
14+
timeExtentMicros: 200,
15+
);
616

717
void main() async {
818
Future<Map<String, dynamic>> request;
@@ -14,10 +24,21 @@ void main() async {
1424
final IntegrationTestWidgetsFlutterBinding integrationBinding =
1525
binding as IntegrationTestWidgetsFlutterBinding;
1626

27+
MockVM mockVM;
28+
List<int> clockTimes = [100, 200];
29+
1730
setUp(() {
1831
request = integrationBinding.callback(<String, String>{
1932
'command': 'request_data',
2033
});
34+
mockVM = MockVM();
35+
when(mockVM.getVMTimeline(
36+
timeOriginMicros: anyNamed('timeOriginMicros'),
37+
timeExtentMicros: anyNamed('timeExtentMicros'),
38+
)).thenAnswer((_) => Future.value(_ktimelines));
39+
when(mockVM.getVMTimelineMicros()).thenAnswer(
40+
(_) => Future.value(vm.Timestamp(timestamp: clockTimes.removeAt(0))),
41+
);
2142
});
2243

2344
testWidgets('Run Integration app', (WidgetTester tester) async {
@@ -53,6 +74,17 @@ void main() async {
5374
expect(widgetCenter.dx, windowCenterX);
5475
expect(widgetCenter.dy, windowCenterY);
5576
});
77+
78+
testWidgets('Test traceAction', (WidgetTester tester) async {
79+
await integrationBinding.enableTimeline(vmService: mockVM);
80+
await integrationBinding.traceAction(() async {});
81+
expect(integrationBinding.reportData, isNotNull);
82+
expect(integrationBinding.reportData.containsKey('timeline'), true);
83+
expect(
84+
json.encode(integrationBinding.reportData['timeline']),
85+
json.encode(_ktimelines),
86+
);
87+
});
5688
});
5789

5890
tearDownAll(() async {
@@ -66,3 +98,5 @@ void main() async {
6698
assert(result.data['answer'] == 42);
6799
});
68100
}
101+
102+
class MockVM extends Mock implements vm.VmService {}

0 commit comments

Comments
 (0)