Skip to content

Commit 7afc855

Browse files
authored
Try golden-testing on a Mokey (bringup: true), retry on an emulator (flutter#163029)
Towards flutter#162362 (see if retries help VD on an emulator). Towards flutter#163025 (see if we can golden-test on a device). May the odds be in our favor.
1 parent af3c910 commit 7afc855

File tree

8 files changed

+115
-19
lines changed

8 files changed

+115
-19
lines changed

.ci.yaml

Lines changed: 14 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -1548,6 +1548,20 @@ targets:
15481548
{"dependency": "goldctl", "version": "git_revision:2387d6fff449587eecbb7e45b2692ca0710b63b9"}
15491549
]
15501550
1551+
- name: Linux_mokey android_engine_vulkan_tests
1552+
recipe: flutter/flutter_drone
1553+
# TODO(matanlurey): https://github.com/flutter/flutter/issues/163025.
1554+
bringup: true
1555+
timeout: 60
1556+
properties:
1557+
shard: android_engine_vulkan_tests
1558+
tags: >
1559+
["framework", "hostonly", "shard", "linux"]
1560+
dependencies: >-
1561+
[
1562+
{"dependency": "goldctl", "version": "git_revision:2387d6fff449587eecbb7e45b2692ca0710b63b9"}
1563+
]
1564+
15511565
- name: Linux_android_emu android_engine_opengles_tests
15521566
recipe: flutter/flutter_drone
15531567
timeout: 60

dev/integration_tests/android_engine_test/android/app/src/main/kotlin/com/example/native_driver_test/extensions/NativeDriverSupportPlugin.kt

Lines changed: 8 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -49,6 +49,14 @@ class NativeDriverSupportPlugin :
4949
val versionMap = mapOf("version" to Build.VERSION.SDK_INT)
5050
result.success(versionMap)
5151
}
52+
"is_emulator" -> {
53+
val isEmulator =
54+
when {
55+
Build.MODEL.contains("gphone") -> true
56+
else -> false
57+
}
58+
result.success(mapOf("emulator" to isEmulator))
59+
}
5260
"ping" -> {
5361
result.success(null)
5462
}
Lines changed: 56 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,56 @@
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+
5+
/// @docImport 'package:android_driver_extensions/skia_gold.dart';
6+
library;
7+
8+
// Similar to `flutter_test`, we ignore the implementation import.
9+
// ignore: implementation_imports
10+
import 'package:android_driver_extensions/native_driver.dart';
11+
import 'package:matcher/src/expect/async_matcher.dart';
12+
import 'package:matcher/src/interfaces.dart';
13+
14+
/// Invokes [matchesGoldenFile] with optional [retries] if a comparison fails.
15+
AsyncMatcher matchesGoldenFileWithRetries(Object key, {int? version, int retries = 2}) {
16+
final AsyncMatcher delegate = matchesGoldenFile(key, version: version);
17+
if (retries == 0) {
18+
return delegate;
19+
}
20+
return _AsyncMatcherWithRetries(delegate, retries: retries);
21+
}
22+
23+
final class _AsyncMatcherWithRetries extends AsyncMatcher {
24+
_AsyncMatcherWithRetries(this._delegate, {required int retries}) : _retries = retries {
25+
if (retries < 1) {
26+
throw RangeError.value(retries, 'retries', 'Must be at least 1');
27+
}
28+
}
29+
30+
final AsyncMatcher _delegate;
31+
int _retries;
32+
33+
@override
34+
Description describe(Description description) {
35+
description = _delegate.describe(description);
36+
description.add('Retries remaining: $_retries');
37+
return description;
38+
}
39+
40+
@override
41+
Future<String?> matchAsync(Object? item) async {
42+
while (true) {
43+
final Object? error = await _delegate.matchAsync(item);
44+
if (error == null) {
45+
return null;
46+
}
47+
print('Failed: $error');
48+
if (--_retries == 0) {
49+
return 'Retries exceeded. Giving up.';
50+
} else {
51+
print('Retrying... $_retries retries left.');
52+
}
53+
assert(_retries >= 0, 'Unreachable');
54+
}
55+
}
56+
}

dev/integration_tests/android_engine_test/test_driver/platform_view/hybrid_composition_platform_view_main_test.dart

Lines changed: 5 additions & 16 deletions
Original file line numberDiff line numberDiff line change
@@ -8,6 +8,7 @@ import 'package:flutter_driver/flutter_driver.dart';
88
import 'package:test/test.dart';
99

1010
import '../_luci_skia_gold_prelude.dart';
11+
import '../_unstable_gold_retry.dart';
1112

1213
/// For local debugging, a (local) golden-file is required as a baseline:
1314
///
@@ -49,22 +50,10 @@ void main() async {
4950
// See:
5051
// - Vulkan: https://github.com/flutter/flutter/issues/162362
5152
// - OpenGLES: https://github.com/flutter/flutter/issues/162363
52-
int retriesLeft = 2;
53-
do {
54-
try {
55-
await expectLater(
56-
nativeDriver.screenshot(),
57-
matchesGoldenFile('$goldenPrefix.blue_orange_gradient_portrait.png'),
58-
);
59-
break;
60-
} on TestFailure catch (e) {
61-
if (retriesLeft == 0) {
62-
rethrow;
63-
}
64-
print('Caught: $e. Retrying...');
65-
retriesLeft--;
66-
}
67-
} while (retriesLeft > 0);
53+
await expectLater(
54+
nativeDriver.screenshot(),
55+
matchesGoldenFileWithRetries('$goldenPrefix.blue_orange_gradient_portrait.png'),
56+
);
6857
}, timeout: Timeout.none);
6958

7059
test('should rotate landscape and screenshot the gradient', () async {

dev/integration_tests/android_engine_test/test_driver/platform_view/virtual_display_platform_view_main_test.dart

Lines changed: 19 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -8,6 +8,7 @@ import 'package:flutter_driver/flutter_driver.dart';
88
import 'package:test/test.dart';
99

1010
import '../_luci_skia_gold_prelude.dart';
11+
import '../_unstable_gold_retry.dart';
1112

1213
/// For local debugging, a (local) golden-file is required as a baseline:
1314
///
@@ -28,6 +29,9 @@ void main() async {
2829
late final FlutterDriver flutterDriver;
2930
late final NativeDriver nativeDriver;
3031

32+
late final bool isEmulator;
33+
late final bool isVulkan;
34+
3135
setUpAll(() async {
3236
if (isLuci) {
3337
await enableSkiaGoldComparator(namePrefix: 'android_engine_test$goldenVariant');
@@ -42,6 +46,13 @@ void main() async {
4246
if (await nativeDriver.sdkVersion case final int version when version < 23) {
4347
fail('Requires SDK >= 23, got $version');
4448
}
49+
50+
// TODO(matanlurey): https://github.com/flutter/flutter/issues/162362#issuecomment-2649555821.
51+
isEmulator = await nativeDriver.isEmulator;
52+
isVulkan = goldenVariant.contains('vulkan');
53+
if (isEmulator && isVulkan) {
54+
print('Detected running on a vulkan emulator. Will retry certain failures');
55+
}
4556
});
4657

4758
tearDownAll(() async {
@@ -60,13 +71,19 @@ void main() async {
6071
await nativeDriver.rotateToLandscape();
6172
await expectLater(
6273
nativeDriver.screenshot(),
63-
matchesGoldenFile('$goldenPrefix.blue_orange_gradient_landscape_rotated.png'),
74+
matchesGoldenFileWithRetries(
75+
'$goldenPrefix.blue_orange_gradient_landscape_rotated.png',
76+
retries: isEmulator && isVulkan ? 2 : 0,
77+
),
6478
);
6579

6680
await nativeDriver.rotateResetDefault();
6781
await expectLater(
6882
nativeDriver.screenshot(),
69-
matchesGoldenFile('$goldenPrefix.blue_orange_gradient_portait_rotated_back.png'),
83+
matchesGoldenFileWithRetries(
84+
'$goldenPrefix.blue_orange_gradient_portait_rotated_back.png',
85+
retries: isEmulator && isVulkan ? 2 : 0,
86+
),
7087
);
7188
}, timeout: Timeout.none);
7289
}

dev/tools/android_driver_extensions/lib/src/backend/android/driver.dart

Lines changed: 6 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -77,6 +77,12 @@ final class AndroidNativeDriver implements NativeDriver {
7777
return result['version']! as int;
7878
}
7979

80+
@override
81+
Future<bool> get isEmulator async {
82+
final Map<String, Object?> result = await _driver.sendCommand(NativeCommand.getIsEmulator);
83+
return result['emulator']! as bool;
84+
}
85+
8086
/// Waits for 2 seconds before completing.
8187
///
8288
/// There is no perfect way, outside of polling, to know when the device is

dev/tools/android_driver_extensions/lib/src/common.dart

Lines changed: 3 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -30,6 +30,9 @@ final class NativeCommand extends Command {
3030
/// Gets the SDK version code.
3131
static const NativeCommand getSdkVersion = NativeCommand('sdk_version');
3232

33+
/// Gets whether the device is an emulator.
34+
static const NativeCommand getIsEmulator = NativeCommand('is_emulator');
35+
3336
/// The method to call on the plugin.
3437
final String method;
3538

dev/tools/android_driver_extensions/lib/src/driver.dart

Lines changed: 4 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -45,9 +45,12 @@ abstract interface class NativeDriver {
4545
/// ```
4646
Future<Duration> ping();
4747

48-
/// Returns the SDK version.
48+
/// The SDK version.
4949
Future<int> get sdkVersion;
5050

51+
/// Whether the device is an emulator.
52+
Future<bool> get isEmulator;
53+
5154
/// Take a screenshot using a platform-specific mechanism.
5255
///
5356
/// The image is returned as an opaque handle that can be used to retrieve

0 commit comments

Comments
 (0)