Unverified Commit b045c14e authored by Ian Hickson's avatar Ian Hickson Committed by GitHub

Make the Skia expectation parser more resilient and update to "master_str". (#62898)

parent 80814553
......@@ -34,6 +34,17 @@ const List<int> _kFailPngBytes =
120, 1, 99, 249, 207, 240, 255, 63, 0, 7, 18, 3, 2, 164, 147, 160, 197, 0,
0, 0, 0, 73, 69, 78, 68, 174, 66, 96, 130];
Future<void> testWithOutput(String name, Future<void> body(), String expectedOutput) async {
test(name, () async {
final StringBuffer output = StringBuffer();
void _recordPrint(Zone self, ZoneDelegate parent, Zone zone, String line) {
output.write(line);
}
await runZoned<Future<void>>(body, zoneSpecification: ZoneSpecification(print: _recordPrint));
expect(output.toString(), expectedOutput);
});
}
void main() {
MemoryFileSystem fs;
FakePlatform platform;
......@@ -341,6 +352,24 @@ void main() {
);
});
test('sets up expectations with temporary key', () async {
url = Uri.parse('https://flutter-gold.skia.org/json/expectations/commit/HEAD');
final MockHttpClientResponse mockHttpResponse = MockHttpClientResponse(
utf8.encode(rawExpectationsTemplateWithTemporaryKey())
);
when(mockHttpClient.getUrl(url))
.thenAnswer((_) => Future<MockHttpClientRequest>.value(mockHttpRequest));
when(mockHttpRequest.close())
.thenAnswer((_) => Future<MockHttpClientResponse>.value(mockHttpResponse));
await skiaClient.getExpectations();
expect(skiaClient.expectations, isNotNull);
expect(
skiaClient.expectations['flutter.golden_test.1'],
contains(expectation),
);
});
test('detects invalid digests SkiaDigest', () {
const String testName = 'flutter.golden_test.2';
final Map<String, dynamic> skiaJson = json.decode(digestResponseTemplate()) as Map<String, dynamic>;
......@@ -851,7 +880,7 @@ void main() {
);
});
test('passes non-existent baseline for new test', () async {
testWithOutput('passes non-existent baseline for new test', () async {
when(mockSkiaClient.cleanTestName('library.flutter.new_golden_test.1.png'))
.thenReturn('flutter.new_golden_test.1');
expect(
......@@ -861,7 +890,8 @@ void main() {
),
isTrue,
);
});
}, 'No expectations provided by Skia Gold for test: library.flutter.new_golden_test.1.png. '
'This may be a new test. If this is an unexpected result, check https://flutter-gold.skia.org.\n');
});
});
......@@ -937,7 +967,7 @@ void main() {
);
});
test('passes non-existent baseline for new test', () async {
testWithOutput('passes non-existent baseline for new test', () async {
expect(
await comparator.compare(
Uint8List.fromList(_kFailPngBytes),
......@@ -945,7 +975,10 @@ void main() {
),
isTrue,
);
});
}, 'No expectations provided by Skia Gold for test: library.flutter.new_golden_test.1. '
'This may be a new test. If this is an unexpected result, check https://flutter-gold.skia.org.\n'
'Validate image output found at flutter/test/library/'
);
test('compare properly awaits validation & output before failing.', () async {
final Completer<bool> completer = Completer<bool>();
......
......@@ -58,6 +58,29 @@ Map<String, List<String>> expectationsTemplate() {
};
}
/// Same as [rawExpectationsTemplate] but with the temporary key.
String rawExpectationsTemplateWithTemporaryKey() {
return '''
{
"md5": "a7489b00e03a1846e43500b7c14dd7b0",
"master_str": {
"flutter.golden_test.1": {
"55109a4bed52acc780530f7a9aeff6c0": 1
},
"flutter.golden_test.3": {
"87cb35131e6ad4b57d4d09d59ae743c3": 1,
"dc94eb2c39c0c8ae11a4efd090b72f94": 1,
"f2583c9003978a06b7888878bdc089e2": 1
},
"flutter.golden_test.2": {
"eb03a5e3114c9ecad5e4f1178f285a49": 1,
"f14631979de24fca6e14ad247d5f2bd6": 1
}
}
}
''';
}
/// Json response template for Skia Gold digest request:
/// https://flutter-gold.skia.org/json/details?test=[testName]&digest=[expectation]
String digestResponseTemplate({
......
......@@ -438,20 +438,30 @@ class SkiaGoldClient {
final Uri requestForExpectations = Uri.parse(
'https://flutter-gold.skia.org/json/expectations/commit/HEAD'
);
const String mainKey = 'master';
const String temporaryKey = 'master_str';
String rawResponse;
try {
final io.HttpClientRequest request = await httpClient.getUrl(requestForExpectations);
final io.HttpClientResponse response = await request.close();
rawResponse = await utf8.decodeStream(response);
final Map<String, dynamic> skiaJson = json.decode(rawResponse)['master'] as Map<String, dynamic>;
final dynamic jsonResponse = json.decode(rawResponse);
if (jsonResponse is! Map<String, dynamic>)
throw const FormatException('Skia gold expectations do not match expected format.');
final Map<String, dynamic> skiaJson = (jsonResponse[mainKey] ?? jsonResponse[temporaryKey]) as Map<String, dynamic>;
if (skiaJson == null)
throw FormatException('Skia gold expectations are missing the "$mainKey" key (and also doesn\'t have "$temporaryKey")! Available keys: ${jsonResponse.keys.join(", ")}');
skiaJson.forEach((String key, dynamic value) {
final Map<String, dynamic> hashesMap = value as Map<String, dynamic>;
_expectations[key] = hashesMap.keys.toList();
});
} on FormatException catch(_) {
print('Formatting error detected requesting expectations from Flutter Gold.\n'
'rawResponse: $rawResponse');
} on FormatException catch (error) {
print(
'Formatting error detected requesting expectations from Flutter Gold.\n'
'error: $error\n'
'url: $requestForExpectations\n'
'response: $rawResponse'
);
rethrow;
}
},
......
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