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

Commit b28cfbb

Browse files
authored
Better filtering for Android scenario_app runner. (#50937)
_🍴 'd from #50933, will rebase when merged._ Closes flutter/flutter#143458. A picture is a 1000 words: ![Screenshot 2024-02-23 at 7 01 29 PM](https://github.com/flutter/engine/assets/168174/7254b3be-cc49-4bad-ae43-e61ac4a853ad) This is still noisy, but at least all the output appears to be part of the execution. As you recall, the full logs are always available in the FLUTTER_LOGS_DIR output.
1 parent a04fba4 commit b28cfbb

File tree

4 files changed

+261
-97
lines changed

4 files changed

+261
-97
lines changed

testing/scenario_app/bin/run_android_tests.dart

Lines changed: 110 additions & 85 deletions
Original file line numberDiff line numberDiff line change
@@ -47,48 +47,52 @@ void main(List<String> args) async {
4747
..addOption(
4848
'adb',
4949
help: 'Path to the adb tool',
50-
defaultsTo: engine != null ? join(
51-
engine.srcDir.path,
52-
'third_party',
53-
'android_tools',
54-
'sdk',
55-
'platform-tools',
56-
'adb',
57-
) : null,
50+
defaultsTo: engine != null
51+
? join(
52+
engine.srcDir.path,
53+
'third_party',
54+
'android_tools',
55+
'sdk',
56+
'platform-tools',
57+
'adb',
58+
)
59+
: null,
5860
)
5961
..addOption(
6062
'ndk-stack',
6163
help: 'Path to the ndk-stack tool',
62-
defaultsTo: engine != null ? join(
63-
engine.srcDir.path,
64-
'third_party',
65-
'android_tools',
66-
'ndk',
67-
'prebuilt',
68-
() {
69-
if (Platform.isLinux) {
70-
return 'linux-x86_64';
71-
} else if (Platform.isMacOS) {
72-
return 'darwin-x86_64';
73-
} else if (Platform.isWindows) {
74-
return 'windows-x86_64';
75-
} else {
76-
throw UnsupportedError('Unsupported platform: ${Platform.operatingSystem}');
77-
}
78-
}(),
79-
'bin',
80-
'ndk-stack',
81-
) : null,
64+
defaultsTo: engine != null
65+
? join(
66+
engine.srcDir.path,
67+
'third_party',
68+
'android_tools',
69+
'ndk',
70+
'prebuilt',
71+
() {
72+
if (Platform.isLinux) {
73+
return 'linux-x86_64';
74+
} else if (Platform.isMacOS) {
75+
return 'darwin-x86_64';
76+
} else if (Platform.isWindows) {
77+
return 'windows-x86_64';
78+
} else {
79+
throw UnsupportedError('Unsupported platform: ${Platform.operatingSystem}');
80+
}
81+
}(),
82+
'bin',
83+
'ndk-stack',
84+
)
85+
: null,
8286
)
8387
..addOption(
8488
'out-dir',
8589
help: 'Out directory',
86-
defaultsTo:
87-
engine?.
88-
outputs().
89-
where((Output o) => basename(o.path.path).startsWith('android_')).
90-
firstOrNull?.
91-
path.path,
90+
defaultsTo: engine
91+
?.outputs()
92+
.where((Output o) => basename(o.path.path).startsWith('android_'))
93+
.firstOrNull
94+
?.path
95+
.path,
9296
)
9397
..addOption(
9498
'smoke-test',
@@ -106,14 +110,16 @@ void main(List<String> args) async {
106110
..addOption(
107111
'output-contents-golden',
108112
help: 'Path to a file that contains the expected filenames of golden files.',
109-
defaultsTo: engine != null ? join(
110-
engine.srcDir.path,
111-
'flutter',
112-
'testing',
113-
'scenario_app',
114-
'android',
115-
'expected_golden_output.txt',
116-
) : null,
113+
defaultsTo: engine != null
114+
? join(
115+
engine.srcDir.path,
116+
'flutter',
117+
'testing',
118+
'scenario_app',
119+
'android',
120+
'expected_golden_output.txt',
121+
)
122+
: null,
117123
)
118124
..addOption(
119125
'impeller-backend',
@@ -124,8 +130,8 @@ void main(List<String> args) async {
124130
..addOption(
125131
'logs-dir',
126132
help: 'The directory to store the logs and screenshots. Defaults to '
127-
'the value of the FLUTTER_LOGS_DIR environment variable, if set, '
128-
'otherwise it defaults to a path within out-dir.',
133+
'the value of the FLUTTER_LOGS_DIR environment variable, if set, '
134+
'otherwise it defaults to a path within out-dir.',
129135
defaultsTo: Platform.environment['FLUTTER_LOGS_DIR'],
130136
);
131137

@@ -153,7 +159,10 @@ void main(List<String> args) async {
153159
final String? contentsGolden = results['output-contents-golden'] as String?;
154160
final _ImpellerBackend? impellerBackend = _ImpellerBackend.tryParse(results['impeller-backend'] as String?);
155161
if (enableImpeller && impellerBackend == null) {
156-
panic(<String>['invalid graphics-backend', results['impeller-backend'] as String? ?? '<null>']);
162+
panic(<String>[
163+
'invalid graphics-backend',
164+
results['impeller-backend'] as String? ?? '<null>'
165+
]);
157166
}
158167
final Directory logsDir = Directory(results['logs-dir'] as String? ?? join(outDir.path, 'scenario_app', 'logs'));
159168
final String? ndkStack = results['ndk-stack'] as String?;
@@ -215,7 +224,10 @@ Future<void> _run({
215224
const ProcessManager pm = LocalProcessManager();
216225

217226
if (!outDir.existsSync()) {
218-
panic(<String>['out-dir does not exist: $outDir', 'make sure to build the selected engine variant']);
227+
panic(<String>[
228+
'out-dir does not exist: $outDir',
229+
'make sure to build the selected engine variant'
230+
]);
219231
}
220232

221233
if (!adb.existsSync()) {
@@ -236,19 +248,25 @@ Future<void> _run({
236248
log('writing logs and screenshots to ${logsDir.path}');
237249

238250
if (!testApk.existsSync()) {
239-
panic(<String>['test apk does not exist: ${testApk.path}', 'make sure to build the selected engine variant']);
251+
panic(<String>[
252+
'test apk does not exist: ${testApk.path}',
253+
'make sure to build the selected engine variant'
254+
]);
240255
}
241256

242257
if (!appApk.existsSync()) {
243-
panic(<String>['app apk does not exist: ${appApk.path}', 'make sure to build the selected engine variant']);
258+
panic(<String>[
259+
'app apk does not exist: ${appApk.path}',
260+
'make sure to build the selected engine variant'
261+
]);
244262
}
245263

246264
// Start a TCP socket in the host, and forward it to the device that runs the tests.
247265
// This allows the test process to start a connection with the host, and write the bytes
248266
// for the screenshots.
249267
// On LUCI, the host uploads the screenshots to Skia Gold.
250268
SkiaGoldClient? skiaGoldClient;
251-
late ServerSocket server;
269+
late ServerSocket server;
252270
final List<Future<void>> pendingComparisons = <Future<void>>[];
253271
await step('Starting server...', () async {
254272
server = await ServerSocket.bind(InternetAddress.anyIPv4, _tcpPort);
@@ -259,7 +277,8 @@ Future<void> _run({
259277
if (verbose) {
260278
stdout.writeln('client connected ${client.remoteAddress.address}:${client.remotePort}');
261279
}
262-
client.transform(const ScreenshotBlobTransformer()).listen((Screenshot screenshot) {
280+
client.transform(const ScreenshotBlobTransformer()).listen(
281+
(Screenshot screenshot) {
263282
final String fileName = screenshot.filename;
264283
final Uint8List fileContent = screenshot.fileContent;
265284
if (verbose) {
@@ -277,18 +296,15 @@ Future<void> _run({
277296
}
278297
if (isSkiaGoldClientAvailable) {
279298
final Future<void> comparison = skiaGoldClient!
280-
.addImg(fileName, goldenFile,
281-
screenshotSize: screenshot.pixelCount)
282-
.catchError((dynamic err) {
283-
panic(<String>['skia gold comparison failed: $err']);
284-
});
299+
.addImg(fileName, goldenFile, screenshotSize: screenshot.pixelCount)
300+
.catchError((dynamic err) {
301+
panic(<String>['skia gold comparison failed: $err']);
302+
});
285303
pendingComparisons.add(comparison);
286304
}
287-
},
288-
onError: (dynamic err) {
305+
}, onError: (dynamic err) {
289306
panic(<String>['error while receiving bytes: $err']);
290-
},
291-
cancelOnError: true);
307+
}, cancelOnError: true);
292308
});
293309
});
294310

@@ -311,27 +327,38 @@ Future<void> _run({
311327
final (Future<int> logcatExitCode, Stream<String> logcatOutput) = getProcessStreams(logcatProcess);
312328

313329
logcatProcessExitCode = logcatExitCode;
330+
String? filterProcessId;
331+
314332
logcatOutput.listen((String line) {
315333
// Always write to the full log.
316334
logcat.writeln(line);
317335

318336
// Conditionally parse and write to stderr.
319337
final AdbLogLine? adbLogLine = AdbLogLine.tryParse(line);
320-
switch (adbLogLine?.process) {
321-
case null:
322-
break;
323-
case 'ActivityManager':
324-
// These are mostly noise, i.e. "D ActivityManager: freezing 24632 com.blah".
325-
if (adbLogLine!.severity == 'D') {
326-
break;
327-
}
328-
// TODO(matanlurey): Figure out why this isn't 'flutter.scenario' or similar.
329-
// Also, why is there two different names?
330-
case 'utter.scenario':
331-
case 'utter.scenarios':
332-
case 'flutter':
333-
case 'FlutterJNI':
334-
log('[adb] $line');
338+
if (verbose || adbLogLine == null) {
339+
log(line);
340+
return;
341+
}
342+
343+
// If we haven't already found a process ID, try to find one.
344+
// The process ID will help us filter out logs from other processes.
345+
filterProcessId ??= adbLogLine.tryParseProcess();
346+
347+
// If this is a "verbose" log, possibly skip it.
348+
final bool isVerbose = adbLogLine.isVerbose(filterProcessId: filterProcessId);
349+
if (isVerbose || filterProcessId == null) {
350+
// We've requested verbose output, so print everything.
351+
if (verbose) {
352+
adbLogLine.printFormatted();
353+
}
354+
return;
355+
}
356+
357+
// It's a non-verbose log, so print it.
358+
adbLogLine.printFormatted();
359+
}, onError: (Object? err) {
360+
if (verbose) {
361+
logWarning('logcat stream error: $err');
335362
}
336363
});
337364
});
@@ -364,10 +391,7 @@ Future<void> _run({
364391
log('using dimensions: ${json.encode(dimensions)}');
365392
skiaGoldClient = SkiaGoldClient(
366393
outDir,
367-
dimensions: <String, String>{
368-
'AndroidAPILevel': connectedDeviceAPILevel,
369-
'GraphicsBackend': enableImpeller ? 'impeller-${impellerBackend!.name}' : 'skia',
370-
},
394+
dimensions: dimensions,
371395
);
372396
});
373397

@@ -412,11 +436,9 @@ Future<void> _run({
412436
'am',
413437
'instrument',
414438
'-w',
415-
if (smokeTestFullPath != null)
416-
'-e class $smokeTestFullPath',
439+
if (smokeTestFullPath != null) '-e class $smokeTestFullPath',
417440
'dev.flutter.scenarios.test/dev.flutter.TestRunner',
418-
if (enableImpeller)
419-
'-e enable-impeller',
441+
if (enableImpeller) '-e enable-impeller',
420442
if (impellerBackend != null)
421443
'-e impeller-backend ${impellerBackend.name}',
422444
]);
@@ -465,22 +487,25 @@ Future<void> _run({
465487
final int exitCode = await pm.runAndForward(<String>[
466488
adb.path,
467489
'reverse',
468-
'--remove', 'tcp:3000',
490+
'--remove',
491+
'tcp:3000',
469492
]);
470493
if (exitCode != 0) {
471494
panic(<String>['could not unforward port']);
472495
}
473496
});
474497

475498
await step('Uninstalling app APK...', () async {
476-
final int exitCode = await pm.runAndForward(<String>[adb.path, 'uninstall', 'dev.flutter.scenarios']);
499+
final int exitCode = await pm.runAndForward(
500+
<String>[adb.path, 'uninstall', 'dev.flutter.scenarios']);
477501
if (exitCode != 0) {
478502
panic(<String>['could not uninstall app apk']);
479503
}
480504
});
481505

482506
await step('Uninstalling test APK...', () async {
483-
final int exitCode = await pm.runAndForward(<String>[adb.path, 'uninstall', 'dev.flutter.scenarios.test']);
507+
final int exitCode = await pm.runAndForward(
508+
<String>[adb.path, 'uninstall', 'dev.flutter.scenarios.test']);
484509
if (exitCode != 0) {
485510
panic(<String>['could not uninstall app apk']);
486511
}

0 commit comments

Comments
 (0)