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

Commit 2f40a27

Browse files
authored
Capture FAILURES!!! when running Android scenario_app tests. (#50255)
I expect `Linux linux_android_emulator_tests` and `Linux linux_android_emulator_tests_api_33` to fail. When they fail, I'll fix the assertion (flutter/flutter#142746) before merging this PR.
1 parent da62280 commit 2f40a27

File tree

7 files changed

+99
-18
lines changed

7 files changed

+99
-18
lines changed

.ci.yaml

Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -60,6 +60,7 @@ targets:
6060
- DEPS
6161
- lib/ui/**
6262
- shell/platform/android/**
63+
- testing/scenario_app/**
6364

6465
# Task to run Linux linux_android_emulator_tests on AVDs running Android 33
6566
# instead of 34 for investigating https://github.com/flutter/flutter/issues/137947.
@@ -76,6 +77,7 @@ targets:
7677
- DEPS
7778
- lib/ui/**
7879
- shell/platform/android/**
80+
- testing/scenario_app/**
7981

8082
- name: Linux builder_cache
8183
enabled_branches:

testing/scenario_app/bin/android_integration_tests.dart

Lines changed: 55 additions & 11 deletions
Original file line numberDiff line numberDiff line change
@@ -18,14 +18,49 @@ import 'utils/screenshot_transformer.dart';
1818
const int tcpPort = 3001;
1919

2020
void main(List<String> args) async {
21-
const ProcessManager pm = LocalProcessManager();
2221
final ArgParser parser = ArgParser()
23-
..addOption('adb', help: 'absolute path to the adb tool', mandatory: true)
24-
..addOption('out-dir', help: 'out directory', mandatory: true);
22+
..addOption(
23+
'adb',
24+
help: 'absolute path to the adb tool',
25+
mandatory: true,
26+
)
27+
..addOption(
28+
'out-dir',
29+
help: 'out directory',
30+
mandatory: true,
31+
)
32+
..addFlag(
33+
'smoke-test',
34+
help: 'runs a single test to verify the setup',
35+
negatable: false,
36+
defaultsTo: true,
37+
);
2538

26-
final ArgResults results = parser.parse(args);
27-
final Directory outDir = Directory(results['out-dir'] as String);
28-
final File adb = File(results['adb'] as String);
39+
runZonedGuarded(
40+
() async {
41+
final ArgResults results = parser.parse(args);
42+
final Directory outDir = Directory(results['out-dir'] as String);
43+
final File adb = File(results['adb'] as String);
44+
final bool smokeTest = results['smoke-test'] as bool;
45+
await _run(outDir: outDir, adb: adb, smokeTest: smokeTest);
46+
exit(0);
47+
},
48+
(Object error, StackTrace stackTrace) {
49+
if (error is! Panic) {
50+
stderr.writeln(error);
51+
stderr.writeln(stackTrace);
52+
}
53+
exit(1);
54+
},
55+
);
56+
}
57+
58+
Future<void> _run({
59+
required Directory outDir,
60+
required File adb,
61+
required bool smokeTest,
62+
}) async {
63+
const ProcessManager pm = LocalProcessManager();
2964

3065
if (!outDir.existsSync()) {
3166
panic(<String>['out-dir does not exist: $outDir', 'make sure to build the selected engine variant']);
@@ -170,15 +205,25 @@ void main(List<String> args) async {
170205
});
171206

172207
await step('Running instrumented tests...', () async {
173-
final int exitCode = await pm.runAndForward(<String>[
208+
final (int exitCode, StringBuffer out) = await pm.runAndCapture(<String>[
174209
adb.path,
175210
'shell',
176211
'am',
177212
'instrument',
178-
'-w', 'dev.flutter.scenarios.test/dev.flutter.TestRunner',
213+
'-w',
214+
if (smokeTest)
215+
'-e class dev.flutter.scenarios.EngineLaunchE2ETest',
216+
'dev.flutter.scenarios.test/dev.flutter.TestRunner',
179217
]);
180218
if (exitCode != 0) {
181-
panic(<String>['could not install test apk']);
219+
panic(<String>['instrumented tests failed to run']);
220+
}
221+
// Unfortunately adb shell am instrument does not return a non-zero exit
222+
// code when tests fail, but it does seem to print "FAILURES!!!" to
223+
// stdout, so we can use that as a signal that something went wrong.
224+
if (out.toString().contains('FAILURES!!!')) {
225+
stdout.write(out);
226+
panic(<String>['1 or more tests failed']);
182227
}
183228
});
184229
} finally {
@@ -221,8 +266,7 @@ void main(List<String> args) async {
221266

222267
await step('Flush logcat...', () async {
223268
await logcat.flush();
269+
await logcat.close();
224270
});
225-
226-
exit(0);
227271
}
228272
}

testing/scenario_app/bin/utils/logs.dart

Lines changed: 3 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -23,9 +23,11 @@ void log(String msg) {
2323
stdout.writeln('$_gray$msg$_reset');
2424
}
2525

26+
final class Panic extends Error {}
27+
2628
void panic(List<String> messages) {
2729
for (final String message in messages) {
2830
stderr.writeln('$_red$message$_reset');
2931
}
30-
throw 'panic';
32+
throw Panic();
3133
}

testing/scenario_app/bin/utils/process_manager_extension.dart

Lines changed: 7 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -45,4 +45,11 @@ extension RunAndForward on ProcessManager {
4545
Future<int> runAndForward(List<String> cmd) async {
4646
return pipeProcessStreams(await start(cmd), out: stdout);
4747
}
48+
49+
/// Runs [cmd], and captures the stdout and stderr pipes.
50+
Future<(int, StringBuffer)> runAndCapture(List<String> cmd) async {
51+
final StringBuffer buffer = StringBuffer();
52+
final int exitCode = await pipeProcessStreams(await start(cmd), out: buffer);
53+
return (exitCode, buffer);
54+
}
4855
}

testing/scenario_app/lib/main.dart

Lines changed: 10 additions & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -25,14 +25,19 @@ void main() {
2525
channelBuffers.setListener('driver', _handleDriverMessage);
2626
channelBuffers.setListener('write_timeline', _handleWriteTimelineMessage);
2727

28-
final FlutterView view = PlatformDispatcher.instance.implicitView!;
28+
// TODO(matanlurey): https://github.com/flutter/flutter/issues/142746.
29+
// This Dart program is used for every test, but there is at least one test
30+
// (EngineLaunchE2ETest.java) that does not create a FlutterView, so the
31+
// implicit view's size is not initialized (and the assert would be tripped).
32+
//
33+
// final FlutterView view = PlatformDispatcher.instance.implicitView!;
2934
// Asserting that this is greater than zero since this app runs on different
3035
// platforms with different sizes. If it is greater than zero, it has been
3136
// initialized to some meaningful value at least.
32-
assert(
33-
view.display.size > Offset.zero,
34-
'Expected ${view.display} to be initialized.',
35-
);
37+
// assert(
38+
// view.display.size > Offset.zero,
39+
// 'Expected ${view.display} to be initialized.',
40+
// );
3641

3742
final ByteData data = ByteData(1);
3843
data.setUint8(0, 1);

testing/scenario_app/run_android_tests.sh

Lines changed: 4 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -33,7 +33,10 @@ function follow_links() (
3333
)
3434

3535
SCRIPT_DIR=$(follow_links "$(dirname -- "${BASH_SOURCE[0]}")")
36-
SRC_DIR="$(cd "$SCRIPT_DIR/../../.."; pwd -P)"
36+
SRC_DIR="$(
37+
cd "$SCRIPT_DIR/../../.."
38+
pwd -P
39+
)"
3740
OUT_DIR="$SRC_DIR/out/$BUILD_VARIANT"
3841

3942
# Dump the logcat and symbolize stack traces before exiting.
Lines changed: 18 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,18 @@
1+
#!/bin/bash
2+
# Copyright 2013 The Flutter Authors. All rights reserved.
3+
# Use of this source code is governed by a BSD-style license that can be
4+
# found in the LICENSE file.
5+
6+
# This is a debugging script that runs a single Android E2E test on a connected
7+
# device or emulator, and reports the exit code. It was largely created to debug
8+
# why `./testing/scenario_app/run_android_tests.sh` did or did not report
9+
# failures correctly.
10+
11+
# Run this command and print out the exit code.
12+
../third_party/dart/tools/sdks/dart-sdk/bin/dart ./testing/scenario_app/bin/android_integration_tests.dart \
13+
--adb="../third_party/android_tools/sdk/platform-tools/adb" \
14+
--out-dir="../out/android_debug_unopt_arm64" \
15+
--smoke-test
16+
17+
echo "Exit code: $?"
18+
echo "Done"

0 commit comments

Comments
 (0)