Index: tools/gardening/bin/compare_failures.dart |
diff --git a/tools/gardening/bin/compare_failures.dart b/tools/gardening/bin/compare_failures.dart |
index de888914be7afeb83cc238627fb96899dad3d456..67f39db33493887731faaf9f30af4b6d4ccc01a6 100644 |
--- a/tools/gardening/bin/compare_failures.dart |
+++ b/tools/gardening/bin/compare_failures.dart |
@@ -6,12 +6,11 @@ |
/// |
/// Use this to detect flakiness of failures, especially timeouts. |
-import 'dart:async'; |
import 'dart:io'; |
import 'package:args/args.dart'; |
-import 'package:gardening/src/buildbot_structures.dart'; |
import 'package:gardening/src/client.dart'; |
+import 'package:gardening/src/compare_failures_impl.dart'; |
import 'package:gardening/src/util.dart'; |
void help(ArgParser argParser) { |
@@ -19,9 +18,11 @@ void help(ArgParser argParser) { |
print('fetches earlier runs of the same bot and compares the results.'); |
print('This tool is particularly useful to detect flakes and their '); |
print('frequency.'); |
- print('Usage: compare_failures [options] <log-uri>'); |
- print('where <log-uri> is the uri the stdio output of a failing test step'); |
- print('and options are:'); |
+ print('Usage: compare_failures [options] '); |
+ print(' (<log-uri> [<log-uri> ...] | <build-group> [<build-group> ...])'); |
+ print('where <log-uri> is the uri the stdio output of a failing test step '); |
+ print('and <build-group> is the name of a buildbot group, for instance '); |
+ print('`vm-kernel`, and options are:'); |
print(argParser.usage); |
} |
@@ -32,10 +33,6 @@ main(List<String> args) async { |
ArgResults argResults = argParser.parse(args); |
processArgResults(argResults); |
- BuildbotClient client = argResults['logdog'] |
- ? new LogdogBuildbotClient() |
- : new HttpBuildbotClient(); |
- |
var runCount = int.parse(argResults['run-count'], onError: (_) => null); |
if (argResults.rest.length != 1 || argResults['help'] || runCount == null) { |
@@ -43,116 +40,10 @@ main(List<String> args) async { |
if (argResults['help']) return; |
exit(1); |
} |
- String url = argResults.rest.first; |
- if (!url.endsWith('/text')) { |
- // Use the text version of the stdio log. |
- url += '/text'; |
- } |
- Uri uri = Uri.parse(url); |
- BuildUri buildUri = new BuildUri(uri); |
- List<BuildResult> results = |
- await readBuildResults(client, buildUri, runCount); |
- print(generateBuildResultsSummary(buildUri, results)); |
- client.close(); |
-} |
- |
-/// Creates a [BuildResult] for [buildUri] and, if it contains failures, the |
-/// [BuildResult]s for the previous [runCount] builds. |
-Future<List<BuildResult>> readBuildResults( |
- BuildbotClient client, BuildUri buildUri, int runCount) async { |
- List<BuildResult> summaries = <BuildResult>[]; |
- BuildResult summary = await client.readResult(buildUri); |
- summaries.add(summary); |
- if (summary.hasFailures) { |
- for (int i = 0; i < runCount; i++) { |
- buildUri = summary.buildUri.prev(); |
- summary = await client.readResult(buildUri); |
- summaries.add(summary); |
- } |
- } |
- return summaries; |
-} |
-/// Generate a summary of the timeouts and other failures in [results]. |
-String generateBuildResultsSummary( |
- BuildUri buildUri, List<BuildResult> results) { |
- StringBuffer sb = new StringBuffer(); |
- sb.write('Results for $buildUri:\n'); |
- Set<TestConfiguration> timeoutIds = new Set<TestConfiguration>(); |
- for (BuildResult result in results) { |
- timeoutIds.addAll(result.timeouts.map((TestFailure failure) => failure.id)); |
- } |
- if (timeoutIds.isNotEmpty) { |
- Map<TestConfiguration, Map<int, Map<String, Timing>>> map = |
- <TestConfiguration, Map<int, Map<String, Timing>>>{}; |
- Set<String> stepNames = new Set<String>(); |
- for (BuildResult result in results) { |
- for (Timing timing in result.timings) { |
- Map<int, Map<String, Timing>> builds = |
- map.putIfAbsent(timing.step.id, () => <int, Map<String, Timing>>{}); |
- stepNames.add(timing.step.stepName); |
- builds.putIfAbsent(timing.uri.buildNumber, () => <String, Timing>{})[ |
- timing.step.stepName] = timing; |
- } |
- } |
- sb.write('Timeouts for ${buildUri} :\n'); |
- map.forEach((TestConfiguration id, Map<int, Map<String, Timing>> timings) { |
- if (!timeoutIds.contains(id)) return; |
- sb.write('$id\n'); |
- sb.write( |
- '${' ' * 8} ${stepNames.map((t) => padRight(t, 14)).join(' ')}\n'); |
- for (BuildResult result in results) { |
- int buildNumber = result.buildUri.buildNumber; |
- Map<String, Timing> steps = timings[buildNumber] ?? const {}; |
- sb.write(padRight(' ${buildNumber}: ', 8)); |
- for (String stepName in stepNames) { |
- Timing timing = steps[stepName]; |
- if (timing != null) { |
- sb.write(' ${timing.time}'); |
- } else { |
- sb.write(' --------------'); |
- } |
- } |
- sb.write('\n'); |
- } |
- sb.write('\n'); |
- }); |
- } |
- Set<TestConfiguration> errorIds = new Set<TestConfiguration>(); |
- for (BuildResult result in results) { |
- errorIds.addAll(result.errors.map((TestFailure failure) => failure.id)); |
- } |
- if (errorIds.isNotEmpty) { |
- Map<TestConfiguration, Map<int, TestFailure>> map = |
- <TestConfiguration, Map<int, TestFailure>>{}; |
- for (BuildResult result in results) { |
- for (TestFailure failure in result.errors) { |
- map.putIfAbsent(failure.id, () => <int, TestFailure>{})[ |
- failure.uri.buildNumber] = failure; |
- } |
- } |
- sb.write('Errors for ${buildUri} :\n'); |
- // TODO(johnniwinther): Improve comparison of non-timeouts. |
- map.forEach((TestConfiguration id, Map<int, TestFailure> failures) { |
- if (!errorIds.contains(id)) return; |
- sb.write('$id\n'); |
- for (BuildResult result in results) { |
- int buildNumber = result.buildUri.buildNumber; |
- TestFailure failure = failures[buildNumber]; |
- sb.write(padRight(' ${buildNumber}: ', 8)); |
- if (failure != null) { |
- sb.write(padRight(failure.expected, 10)); |
- sb.write(' / '); |
- sb.write(padRight(failure.actual, 10)); |
- } else { |
- sb.write(' ' * 10); |
- sb.write(' / '); |
- sb.write(padRight('-- OK --', 10)); |
- } |
- sb.write('\n'); |
- } |
- sb.write('\n'); |
- }); |
- } |
- return sb.toString(); |
+ BuildbotClient client = argResults['logdog'] |
+ ? new LogdogBuildbotClient() |
+ : new HttpBuildbotClient(); |
+ await mainInternal(client, argResults.rest, runCount: runCount); |
+ client.close(); |
} |