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

Commit

Permalink
[integration_test] add support to get timeline (#2947)
Browse files Browse the repository at this point in the history
  • Loading branch information
CareF committed Aug 28, 2020
1 parent 9d1f131 commit e8306b5
Show file tree
Hide file tree
Showing 5 changed files with 151 additions and 13 deletions.
4 changes: 4 additions & 0 deletions packages/integration_test/CHANGELOG.md
Original file line number Diff line number Diff line change
@@ -1,3 +1,7 @@
## 0.8.2

* Add support to get timeline.

## 0.8.1

* Show stack trace of widget test errors on the platform side
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -13,22 +13,29 @@ import 'package:integration_test/integration_test.dart';
import 'package:integration_test_example/main.dart' as app;

void main() {
IntegrationTestWidgetsFlutterBinding.ensureInitialized();
final IntegrationTestWidgetsFlutterBinding binding =
IntegrationTestWidgetsFlutterBinding.ensureInitialized()
as IntegrationTestWidgetsFlutterBinding;
testWidgets('verify text', (WidgetTester tester) async {
// Build our app and trigger a frame.
app.main();

// Trigger a frame.
await tester.pumpAndSettle();
// Trace the timeline of the following operation. The timeline result will
// be written to `build/integration_response_data.json` with the key
// `timeline`.
await binding.traceAction(() async {
// Trigger a frame.
await tester.pumpAndSettle();

// Verify that platform version is retrieved.
expect(
find.byWidgetPredicate(
(Widget widget) =>
widget is Text &&
widget.data.startsWith('Platform: ${Platform.operatingSystem}'),
),
findsOneWidget,
);
// Verify that platform version is retrieved.
expect(
find.byWidgetPredicate(
(Widget widget) =>
widget is Text &&
widget.data.startsWith('Platform: ${Platform.operatingSystem}'),
),
findsOneWidget,
);
});
});
}
91 changes: 91 additions & 0 deletions packages/integration_test/lib/integration_test.dart
Original file line number Diff line number Diff line change
Expand Up @@ -3,12 +3,15 @@
// found in the LICENSE file.

import 'dart:async';
import 'dart:developer' as developer;

import 'package:flutter/rendering.dart';
import 'package:flutter_test/flutter_test.dart';
import 'package:flutter/foundation.dart';
import 'package:flutter/services.dart';
import 'package:flutter/widgets.dart';
import 'package:vm_service/vm_service.dart' as vm;
import 'package:vm_service/vm_service_io.dart' as vm_io;

import 'common.dart';
import '_extension_io.dart' if (dart.library.html) '_extension_web.dart';
Expand Down Expand Up @@ -191,4 +194,92 @@ class IntegrationTestWidgetsFlutterBinding
);
results[description] ??= _success;
}

vm.VmService _vmService;

/// Initialize the [vm.VmService] settings for the timeline.
@visibleForTesting
Future<void> enableTimeline({
List<String> streams = const <String>['all'],
@visibleForTesting vm.VmService vmService,
}) async {
assert(streams != null);
assert(streams.isNotEmpty);
if (vmService != null) {
_vmService = vmService;
}
if (_vmService == null) {
final developer.ServiceProtocolInfo info =
await developer.Service.getInfo();
assert(info.serverUri != null);
_vmService = await vm_io.vmServiceConnectUri(
'ws://localhost:${info.serverUri.port}${info.serverUri.path}ws',
);
}
await _vmService.setVMTimelineFlags(streams);
}

/// Runs [action] and returns a [vm.Timeline] trace for it.
///
/// Waits for the `Future` returned by [action] to complete prior to stopping
/// the trace.
///
/// The `streams` parameter limits the recorded timeline event streams to only
/// the ones listed. By default, all streams are recorded.
/// See `timeline_streams` in
/// [Dart-SDK/runtime/vm/timeline.cc](https://github.com/dart-lang/sdk/blob/master/runtime/vm/timeline.cc)
///
/// If [retainPriorEvents] is true, retains events recorded prior to calling
/// [action]. Otherwise, prior events are cleared before calling [action]. By
/// default, prior events are cleared.
Future<vm.Timeline> traceTimeline(
Future<dynamic> action(), {
List<String> streams = const <String>['all'],
bool retainPriorEvents = false,
}) async {
await enableTimeline(streams: streams);
if (retainPriorEvents) {
await action();
return await _vmService.getVMTimeline();
}

await _vmService.clearVMTimeline();
final vm.Timestamp startTime = await _vmService.getVMTimelineMicros();
await action();
final vm.Timestamp endTime = await _vmService.getVMTimelineMicros();
return await _vmService.getVMTimeline(
timeOriginMicros: startTime.timestamp,
timeExtentMicros: endTime.timestamp,
);
}

/// This is a convenience wrap of [traceTimeline] and send the result back to
/// the host for the [flutter_driver] style tests.
///
/// This records the timeline during `action` and adds the result to
/// [reportData] with `reportKey`. [reportData] contains the extra information
/// of the test other than test success/fail. It will be passed back to the
/// host and be processed by the [ResponseDataCallback] defined in
/// [integrationDriver]. By default it will be written to
/// `build/integration_response_data.json` with the key `timeline`.
///
/// For tests with multiple calls of this method, `reportKey` needs to be a
/// unique key, otherwise the later result will override earlier one.
///
/// The `streams` and `retainPriorEvents` parameters are passed as-is to
/// [traceTimeline].
Future<void> traceAction(
Future<dynamic> action(), {
List<String> streams = const <String>['all'],
bool retainPriorEvents = false,
String reportKey = 'timeline',
}) async {
vm.Timeline timeline = await traceTimeline(
action,
streams: streams,
retainPriorEvents: retainPriorEvents,
);
reportData ??= <String, dynamic>{};
reportData[reportKey] = timeline.toJson();
}
}
4 changes: 3 additions & 1 deletion packages/integration_test/pubspec.yaml
Original file line number Diff line number Diff line change
@@ -1,6 +1,6 @@
name: integration_test
description: Runs tests that use the flutter_test API as integration tests.
version: 0.8.1
version: 0.8.2
homepage: https://github.com/flutter/plugins/tree/master/packages/integration_test

environment:
Expand All @@ -15,9 +15,11 @@ dependencies:
flutter_test:
sdk: flutter
path: ^1.6.4
vm_service: ^4.2.0

dev_dependencies:
pedantic: ^1.8.0
mockito: ^4.1.1

flutter:
plugin:
Expand Down
34 changes: 34 additions & 0 deletions packages/integration_test/test/binding_test.dart
Original file line number Diff line number Diff line change
@@ -1,8 +1,18 @@
import 'dart:convert';

import 'package:flutter/material.dart';

import 'package:integration_test/integration_test.dart';
import 'package:integration_test/common.dart';
import 'package:flutter_test/flutter_test.dart';
import 'package:mockito/mockito.dart';
import 'package:vm_service/vm_service.dart' as vm;

vm.Timeline _ktimelines = vm.Timeline(
traceEvents: <vm.TimelineEvent>[],
timeOriginMicros: 100,
timeExtentMicros: 200,
);

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

MockVM mockVM;
List<int> clockTimes = [100, 200];

setUp(() {
request = integrationBinding.callback(<String, String>{
'command': 'request_data',
});
mockVM = MockVM();
when(mockVM.getVMTimeline(
timeOriginMicros: anyNamed('timeOriginMicros'),
timeExtentMicros: anyNamed('timeExtentMicros'),
)).thenAnswer((_) => Future.value(_ktimelines));
when(mockVM.getVMTimelineMicros()).thenAnswer(
(_) => Future.value(vm.Timestamp(timestamp: clockTimes.removeAt(0))),
);
});

testWidgets('Run Integration app', (WidgetTester tester) async {
Expand Down Expand Up @@ -53,6 +74,17 @@ void main() async {
expect(widgetCenter.dx, windowCenterX);
expect(widgetCenter.dy, windowCenterY);
});

testWidgets('Test traceAction', (WidgetTester tester) async {
await integrationBinding.enableTimeline(vmService: mockVM);
await integrationBinding.traceAction(() async {});
expect(integrationBinding.reportData, isNotNull);
expect(integrationBinding.reportData.containsKey('timeline'), true);
expect(
json.encode(integrationBinding.reportData['timeline']),
json.encode(_ktimelines),
);
});
});

tearDownAll(() async {
Expand All @@ -66,3 +98,5 @@ void main() async {
assert(result.data['answer'] == 42);
});
}

class MockVM extends Mock implements vm.VmService {}

0 comments on commit e8306b5

Please sign in to comment.