1// Copyright 2014 The Flutter Authors. All rights reserved.
2// Use of this source code is governed by a BSD-style license that can be
3// found in the LICENSE file.
4
5import 'package:file/file.dart';
6import 'package:file/local.dart';
7import 'package:glob/glob.dart';
8import 'package:glob/list_local_fs.dart';
9import 'package:path/path.dart' as path;
10
11import '../run_command.dart';
12import '../utils.dart';
13
14/// To run this test locally:
15///
16/// 1. Connect an Android device or emulator.
17/// 2. Run `dart pub get` in dev/bots
18/// 3. Run the following command from the root of the Flutter repository:
19///
20/// ```sh
21/// # Generate a baseline of local golden files.
22/// SHARD=android_engine_vulkan_tests UPDATE_GOLDENS=1 bin/cache/dart-sdk/bin/dart dev/bots/test.dart
23/// ```
24///
25/// 4. Then, re-run the command against the baseline images:
26///
27/// ```sh
28/// SHARD=android_engine_vulkan_tests bin/cache/dart-sdk/bin/dart dev/bots/test.dart
29/// ```
30///
31/// If you are trying to debug a commit, you will want to run step (3) first,
32/// then apply the commit (or flag), and then run step (4). If you are trying
33/// to determine flakiness in the *same* state, or want better debugging, see
34/// `dev/integration_tests/android_engine_test/README.md`.
35Future<void> runAndroidEngineTests({required ImpellerBackend impellerBackend}) async {
36 print('Running Flutter Driver Android tests (backend=$impellerBackend)');
37
38 final String androidEngineTestPath = path.join('dev', 'integration_tests', 'android_engine_test');
39 final List<FileSystemEntity> mains = Glob('$androidEngineTestPath/lib/**_main.dart').listSync();
40
41 final File androidManifestXml = const LocalFileSystem().file(
42 path.join(androidEngineTestPath, 'android', 'app', 'src', 'main', 'AndroidManifest.xml'),
43 );
44 final String androidManifestContents = androidManifestXml.readAsStringSync();
45
46 try {
47 // Replace whatever the current backend is with the specified backend.
48 final RegExp impellerBackendMetadata = RegExp(_impellerBackendMetadata(value: '.*'));
49 androidManifestXml.writeAsStringSync(
50 androidManifestContents.replaceFirst(
51 impellerBackendMetadata,
52 _impellerBackendMetadata(value: impellerBackend.name),
53 ),
54 );
55
56 // Stdout will produce: "Using the Impeller rendering backend (.*)"
57 // TODO(matanlurey): Enable once `flutter drive` retains error logs.
58 // final RegExp impellerStdoutPattern = RegExp('Using the Imepller rendering backend (.*)');
59
60 Future runTest(FileSystemEntity file) async {
61 final CommandResult result = await runCommand(
62 'flutter',
63 [
64 'drive',
65 path.relative(file.path, from: androidEngineTestPath),
66 // There are no reason to enable development flags for this test.
67 // Disable them to work around flakiness issues, and in general just
68 // make less things start up unnecessarily.
69 '--no-dds',
70 '--no-enable-dart-profiling',
71 '--test-arguments=test',
72 '--test-arguments=--reporter=expanded',
73 ],
74 workingDirectory: androidEngineTestPath,
75 environment: {'ANDROID_ENGINE_TEST_GOLDEN_VARIANT': impellerBackend.name},
76 );
77 final String? stdout = result.flattenedStdout;
78 if (stdout == null) {
79 foundError(['No stdout produced.']);
80 return;
81 }
82
83 // TODO(matanlurey): Enable once `flutter drive` retains error logs.
84 // https://github.com/flutter/flutter/issues/162087.
85 //
86 // final Match? stdoutMatch = impellerStdoutPattern.firstMatch(stdout);
87 // if (stdoutMatch == null) {
88 // foundError(['Could not find pattern ${impellerStdoutPattern.pattern}.', stdout]);
89 // return;
90 // }
91
92 // final String reportedBackend = stdoutMatch.group(1)!.toLowerCase();
93 // if (reportedBackend != impellerBackend.name) {
94 // foundError([
95 // 'Reported Imepller backend was $reportedBackend, expected ${impellerBackend.name}',
96 // ]);
97 // return;
98 // }
99 }
100
101 for (final FileSystemEntity file in mains) {
102 if (file.path.contains('hcpp')) {
103 continue;
104 }
105 await runTest(file);
106 }
107
108 // Test HCPP Platform Views on Vulkan.
109 if (impellerBackend == ImpellerBackend.vulkan) {
110 androidManifestXml.writeAsStringSync(
111 androidManifestXml.readAsStringSync().replaceFirst(
112 kSurfaceControlMetadataDisabled,
113 kSurfaceControlMetadataEnabled,
114 ),
115 );
116 for (final FileSystemEntity file in mains) {
117 if (!file.path.contains('hcpp')) {
118 continue;
119 }
120 await runTest(file);
121 }
122 }
123 } finally {
124 // Restore original contents.
125 androidManifestXml.writeAsStringSync(androidManifestContents);
126 }
127}
128
129const String kSurfaceControlMetadataDisabled =
130 '';
131const String kSurfaceControlMetadataEnabled =
132 '';
133
134String _impellerBackendMetadata({required String value}) {
135 return '';
136}
137
138enum ImpellerBackend { vulkan, opengles }
139