Commit bd8e431d authored by Chris Bracken's avatar Chris Bracken Committed by GitHub

Restrict timeline collection to a subset of demos (#9093)

Also refactors demos list into a class with `synchronized` and
`profiled` properties.

When run with --trace-startup, as we do in this test, the VM stores
trace events in an endless buffer instead of a ring buffer. To avoid
out-of-memory conditions, we restrict timeline collection to a subset.
parent 2993ae8d
...@@ -11,57 +11,72 @@ import 'package:flutter_driver/flutter_driver.dart'; ...@@ -11,57 +11,72 @@ import 'package:flutter_driver/flutter_driver.dart';
import 'package:path/path.dart' as path; import 'package:path/path.dart' as path;
import 'package:test/test.dart'; import 'package:test/test.dart';
class Demo {
const Demo(this.title, {this.synchronized = true, this.profiled = false});
/// The title of the demo.
final String title;
/// True if frameSync should be enabled for this test.
final bool synchronized;
// True if timeline data should be collected for this test.
//
// Warning: The number of tests executed with timeline collection enabled
// significantly impacts heap size of the running app. When run with
// --trace-startup, as we do in this test, the VM stores trace events in an
// endless buffer instead of a ring buffer.
final bool profiled;
}
// Warning: this list must be kept in sync with the value of // Warning: this list must be kept in sync with the value of
// kAllGalleryItems.map((GalleryItem item) => item.title).toList(); // kAllGalleryItems.map((GalleryItem item) => item.title).toList();
final List<String> demoTitles = <String>[ const List<Demo> demos = const <Demo>[
// Demos // Demos
'Pesto', const Demo('Pesto', profiled: true),
'Shrine', const Demo('Shrine', profiled: true),
'Contact profile', const Demo('Contact profile', profiled: true),
'Animation', const Demo('Animation', profiled: true),
// Material Components // Material Components
'Bottom navigation', const Demo('Bottom navigation', profiled: true),
'Buttons', const Demo('Buttons', profiled: true),
'Cards', const Demo('Cards', profiled: true),
'Chips', const Demo('Chips', profiled: true),
'Date and time pickers', const Demo('Date and time pickers', profiled: true),
'Dialog', const Demo('Dialog', profiled: true),
'Drawer', const Demo('Drawer'),
'Expand/collapse list control', const Demo('Expand/collapse list control'),
'Expansion panels', const Demo('Expansion panels'),
'Floating action button', const Demo('Floating action button'),
'Grid', const Demo('Grid'),
'Icons', const Demo('Icons'),
'Leave-behind list items', const Demo('Leave-behind list items'),
'List', const Demo('List'),
'Menus', const Demo('Menus'),
'Modal bottom sheet', const Demo('Modal bottom sheet'),
'Page selector', const Demo('Page selector'),
'Persistent bottom sheet', const Demo('Persistent bottom sheet'),
'Progress indicators', const Demo('Progress indicators', synchronized: false),
'Pull to refresh', const Demo('Pull to refresh'),
'Scrollable tabs', const Demo('Scrollable tabs'),
'Selection controls', const Demo('Selection controls'),
'Sliders', const Demo('Sliders'),
'Snackbar', const Demo('Snackbar'),
'Tabs', const Demo('Tabs'),
'Text fields', const Demo('Text fields'),
'Tooltips', const Demo('Tooltips'),
// Cupertino Components // Cupertino Components
'Activity Indicator', const Demo('Activity Indicator', synchronized: false),
'Buttons', const Demo('Buttons'),
'Dialogs', const Demo('Dialogs'),
'Sliders', const Demo('Sliders'),
'Switches', const Demo('Switches'),
// Style
'Colors',
'Typography'
];
// Subset of [demoTitles] that needs frameSync turned off. // Style
final List<String> unsynchedDemoTitles = <String>[ const Demo('Colors'),
'Progress indicators', const Demo('Typography'),
'Activity Indicator',
]; ];
final FileSystem _fs = const LocalFileSystem(); final FileSystem _fs = const LocalFileSystem();
...@@ -134,6 +149,32 @@ Future<Null> saveDurationsHistogram(List<Map<String, dynamic>> events, String ou ...@@ -134,6 +149,32 @@ Future<Null> saveDurationsHistogram(List<Map<String, dynamic>> events, String ou
await file.writeAsString(const JsonEncoder.withIndent(' ').convert(durations)); await file.writeAsString(const JsonEncoder.withIndent(' ').convert(durations));
} }
/// Scrolls each demo menu item into view, launches it, then returns to the
/// home screen twice.
Future<Null> runDemos(Iterable<Demo> demos, FlutterDriver driver) async {
for (Demo demo in demos) {
print('Testing "${demo.title}" demo');
final SerializableFinder menuItem = find.text(demo.title);
await driver.scrollIntoView(menuItem, alignment: 0.5);
await new Future<Null>.delayed(kWaitBetweenActions);
for (int i = 0; i < 2; i += 1) {
await driver.tap(menuItem); // Launch the demo
await new Future<Null>.delayed(kWaitBetweenActions);
if (demo.synchronized) {
await driver.tap(find.byTooltip('Back'));
} else {
await driver.runUnsynchronized<Future<Null>>(() async {
await new Future<Null>.delayed(kWaitBetweenActions);
await driver.tap(find.byTooltip('Back'));
});
}
await new Future<Null>.delayed(kWaitBetweenActions);
}
print('Success');
}
}
void main() { void main() {
group('flutter gallery transitions', () { group('flutter gallery transitions', () {
FlutterDriver driver; FlutterDriver driver;
...@@ -147,30 +188,10 @@ void main() { ...@@ -147,30 +188,10 @@ void main() {
}); });
test('all demos', () async { test('all demos', () async {
// Collect timeline data for just a limited set of demos to avoid OOMs.
final Timeline timeline = await driver.traceAction(() async { final Timeline timeline = await driver.traceAction(() async {
// Scroll each demo menu item into view, launch the demo and final Iterable<Demo> profiledDemos = demos.where((Demo demo) => demo.profiled);
// return to the demo menu 2x. await runDemos(profiledDemos, driver);
for(String demoTitle in demoTitles) {
print('Testing "$demoTitle" demo');
final SerializableFinder menuItem = find.text(demoTitle);
await driver.scrollIntoView(menuItem, alignment: 0.5);
await new Future<Null>.delayed(kWaitBetweenActions);
for(int i = 0; i < 2; i += 1) {
await driver.tap(menuItem); // Launch the demo
await new Future<Null>.delayed(kWaitBetweenActions);
if (!unsynchedDemoTitles.contains(demoTitle)) {
await driver.tap(find.byTooltip('Back'));
} else {
await driver.runUnsynchronized<Future<Null>>(() async {
await new Future<Null>.delayed(kWaitBetweenActions);
await driver.tap(find.byTooltip('Back'));
});
}
await new Future<Null>.delayed(kWaitBetweenActions);
}
print('Success');
}
}, },
streams: const <TimelineStream>[ streams: const <TimelineStream>[
TimelineStream.dart, TimelineStream.dart,
...@@ -184,6 +205,11 @@ void main() { ...@@ -184,6 +205,11 @@ void main() {
await summary.writeSummaryToFile('transitions', pretty: true); await summary.writeSummaryToFile('transitions', pretty: true);
final String histogramPath = path.join(testOutputsDirectory, 'transition_durations.timeline.json'); final String histogramPath = path.join(testOutputsDirectory, 'transition_durations.timeline.json');
await saveDurationsHistogram(timeline.json['traceEvents'], histogramPath); await saveDurationsHistogram(timeline.json['traceEvents'], histogramPath);
// Execute the remaining tests.
final Iterable<Demo> unprofiledDemos = demos.where((Demo demo) => !demo.profiled);
await runDemos(unprofiledDemos, driver);
}, timeout: const Timeout(const Duration(minutes: 5))); }, timeout: const Timeout(const Duration(minutes: 5)));
}); });
} }
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