blob: 83d3af3d977d0e6f0958b0f4c53f69dbbf74fc17 [file] [log] [blame]
// Copyright (c) 2017, 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.
/// Scans past dart2js-windows test steps for timeouts and reports the
/// frequency of each test that has timed out.
import 'dart:async';
import 'dart:io';
import 'package:args/args.dart';
import 'package:gardening/src/buildbot_data.dart';
import 'package:gardening/src/buildbot_loading.dart';
import 'package:gardening/src/buildbot_structures.dart';
import 'package:gardening/src/client.dart';
import 'package:gardening/src/logdog.dart';
import 'package:gardening/src/util.dart';
// TODO(johnniwinther): Adjustments needed: this script may run with
// no output for a long time. Hence not yet run by bot.dart.
main(List<String> args) async {
ArgParser argParser = createArgParser();
argParser.addOption('start',
defaultsTo: '-2',
help: "Start pulling from the specified <build-number>.\n"
"Use negative numbers for the most recent builds;\n"
"for instance -2 for the second-to-last build.'");
ArgResults argResults = argParser.parse(args);
processArgResults(argResults);
BuildbotClient client = argResults['logdog']
? new LogdogBuildbotClient()
: new HttpBuildbotClient();
List<String> arguments = argResults.rest;
if (arguments.length > 1) {
print('Usage: find_timeouts.dart [options] [<count>]');
print('Where <count> is the number of old builds that are scanned');
print('and options are:');
print(argParser.usage);
exit(1);
}
int buildNumberCount = 10;
if (arguments.length > 0) {
buildNumberCount = int.parse(arguments[0]);
}
int buildNumberOffset;
if (argResults.wasParsed('start')) {
buildNumberOffset = int.parse(argResults['start']);
} else {
buildNumberOffset = client.mostRecentBuildNumber;
}
BuildGroup group =
buildGroups.firstWhere((g) => g.groupName == 'dart2js-windows');
Map<String, List<Timeout>> timeouts = <String, List<Timeout>>{};
for (BuildSubgroup subgroup in group.subgroups) {
await readBuildBotResults(client, subgroup, timeouts,
buildNumberOffset: buildNumberOffset,
buildNumberCount: buildNumberCount);
}
List<String> sorted = timeouts.keys.toList()
..sort((a, b) {
return -timeouts[a].length.compareTo(timeouts[b].length);
});
sorted.forEach((String testName) {
List<Timeout> list = timeouts[testName];
print('${padLeft('${list.length}', 4)} $testName');
for (Timeout timeout in list) {
print(' - ${timeout.buildUri.botName}/${timeout.buildUri.stepName} '
'${timeout.timeout.id} (${timeout.buildNumber})');
}
});
client.close();
}
Future readLogDogResults(
BuildSubgroup subgroup, Map<String, List<Timeout>> timeouts,
{int buildNumberOffset, int buildNumberCount}) async {
Map<String, String> subgroupPaths = subgroup.logDogPaths;
for (String shardName in subgroupPaths.keys) {
List<int> buildNumbers =
await latestBuildNumbersForBuilder(shardName, buildNumberCount);
int buildNumberIndex;
if (buildNumberOffset < 0) {
buildNumberIndex = -buildNumberOffset - 1;
} else {
buildNumberIndex = buildNumbers.firstWhere((n) => n <= buildNumberOffset,
orElse: () => buildNumbers.length);
}
for (int i = 0; i < buildNumberCount; i++) {
if (buildNumberIndex + i < buildNumbers.length) {
int buildNumber = buildNumbers[buildNumberIndex + i];
for (BuildUri buildUri
in subgroup.createShardUris(shardName, buildNumber)) {
BuildResult result = await readBuildResultFromLogDog(buildUri);
for (TestFailure timeout in result.timeouts) {
timeouts.putIfAbsent(timeout.id.testName, () => <Timeout>[]).add(
new Timeout(subgroup, result.buildNumber, buildUri, timeout));
}
buildUri = buildUri.prev();
}
}
}
}
}
Future readBuildBotResults(BuildbotClient client, BuildSubgroup subgroup,
Map<String, List<Timeout>> timeouts,
{int buildNumberOffset, int buildNumberCount}) async {
List<BuildUri> buildUris = subgroup.createUris(buildNumberOffset);
for (BuildUri buildUri in buildUris) {
for (int i = 0; i < buildNumberCount; i++) {
BuildResult result = await client.readResult(buildUri);
for (TestFailure timeout in result.timeouts) {
timeouts
.putIfAbsent(timeout.id.testName, () => <Timeout>[])
.add(new Timeout(subgroup, result.buildNumber, buildUri, timeout));
}
buildUri = result.buildUri.prev();
}
}
}
class Timeout {
final BuildSubgroup subgroup;
final int buildNumber;
final BuildUri buildUri;
final TestFailure timeout;
Timeout(this.subgroup, this.buildNumber, this.buildUri, this.timeout);
}