blob: 4b260e972d98186f53479ee538aa9cc56110238b [file] [log] [blame]
// Copyright (c) 2019, the Dart project authors. Please see the AUTHORS file
// for details. All rights reserved. Use of this source code is governed by a
// BSD-style license that can be found in the LICENSE file.
/// Displays the log for a failing test on a given runner and build
import 'dart:async';
import 'dart:convert';
import 'package:_discoveryapis_commons/_discoveryapis_commons.dart';
import 'package:googleapis/storage/v1.dart' as storage;
import 'package:http/http.dart' as http;
final resultsBucket = 'dart-test-results';
Future<String> getCloudFile(String bucket, String path) async {
final client = http.Client();
try {
final api = storage.StorageApi(client);
final media = await api.objects
.get(bucket, path, downloadOptions: DownloadOptions.FullMedia) as Media;
return await utf8.decodeStream(media.stream);
} finally {
client.close();
}
}
Future<String> getLatestBuildNumber(String builder) =>
getCloudFile(resultsBucket, "builders/$builder/latest");
Future<String> getApproval(String builder) async {
try {
final bucket = "dart-test-results";
String build = await getCloudFile(bucket, "builders/$builder/latest");
return await getCloudFile(
bucket, "builders/$builder/$build/approved_results.json");
} catch (e) {
print(e);
return null;
}
}
/// Fetches a log or logs and formats them for output.
/// If a failure occurs, signal error on the returned future.
Future<String> getLog(
String builder, String build, String configuration, String test) async {
if (build == "latest") {
build = await getLatestBuildNumber(builder);
}
final safeRegExp = RegExp('^[-\\w]*\$');
final digitsRegExp = RegExp('^\\d*\$');
if (!safeRegExp.hasMatch(builder)) {
throw "Builder name $builder contains illegal characters";
}
if (!digitsRegExp.hasMatch(build)) {
throw "Build number $build is not a number";
}
final logs_json =
await getCloudFile(resultsBucket, "builders/$builder/$build/logs.json");
final logs = LineSplitter.split(logs_json)
.where((line) => line.isNotEmpty)
.map(jsonDecode);
var testFilter = (log) => log["name"] == test;
if (test.endsWith("*")) {
final prefix = test.substring(0, test.length - 1);
testFilter = (log) => log["name"].startsWith(prefix);
}
var configurationFilter = (log) => log["configuration"] == configuration;
if (configuration.endsWith("*")) {
final prefix = configuration.substring(0, configuration.length - 1);
configurationFilter = (log) => log["configuration"].startsWith(prefix);
}
var result = logs
.where((log) => testFilter(log) && configurationFilter(log))
.map((log) => log["log"])
.join("\n\n======================================================\n\n");
if (result.isEmpty) return null;
return result;
}