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

Commit 07a3334

Browse files
committed
add support to timeline
1 parent f8341ef commit 07a3334

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

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)