Index: tools/gardening/bin/compare_failures.dart |
diff --git a/tools/gardening/bin/compare_failures.dart b/tools/gardening/bin/compare_failures.dart |
index fc0935fdd4b04e9deaf5e752884986a46e077b1f..8ccf5d66ce898ebf4e27ef016d073cd13e011397 100644 |
--- a/tools/gardening/bin/compare_failures.dart |
+++ b/tools/gardening/bin/compare_failures.dart |
@@ -9,15 +9,23 @@ |
import 'dart:async'; |
import 'dart:io'; |
+import 'package:args/args.dart'; |
import 'package:gardening/src/buildbot_structures.dart'; |
+import 'package:gardening/src/buildbot_loading.dart'; |
import 'package:gardening/src/util.dart'; |
main(List<String> args) async { |
- if (args.length != 1) { |
- print('Usage: compare_failures <log-uri>'); |
+ ArgParser argParser = createArgParser(); |
+ ArgResults argResults = argParser.parse(args); |
+ processArgResults(argResults); |
+ if (argResults.rest.length != 1) { |
+ 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(argParser.usage); |
exit(1); |
} |
- String url = args.first; |
+ String url = argResults.rest.first; |
if (!url.endsWith('/text')) { |
// Use the text version of the stdio log. |
url += '/text'; |
@@ -46,48 +54,6 @@ Future<List<BuildResult>> readBuildResults( |
return summaries; |
} |
-/// Parses the [buildUri] test log and creates a [BuildResult] for it. |
-Future<BuildResult> readBuildResult( |
- HttpClient client, BuildUri buildUri) async { |
- Uri uri = buildUri.toUri(); |
- log('Reading $uri'); |
- String text = await readUriAsText(client, uri); |
- |
- bool inFailure = false; |
- List<String> currentFailure; |
- bool parsingTimingBlock = false; |
- |
- List<TestFailure> failures = <TestFailure>[]; |
- List<Timing> timings = <Timing>[]; |
- for (String line in text.split('\n')) { |
- if (currentFailure != null) { |
- if (line.startsWith('!@@@STEP_CLEAR@@@')) { |
- failures.add(new TestFailure(buildUri, currentFailure)); |
- currentFailure = null; |
- } else { |
- currentFailure.add(line); |
- } |
- } else if (inFailure && line.startsWith('@@@STEP_FAILURE@@@')) { |
- inFailure = false; |
- } else if (line.startsWith('!@@@STEP_FAILURE@@@')) { |
- inFailure = true; |
- } else if (line.startsWith('FAILED:')) { |
- currentFailure = <String>[]; |
- currentFailure.add(line); |
- } |
- if (line.startsWith('--- Total time:')) { |
- parsingTimingBlock = true; |
- } else if (parsingTimingBlock) { |
- if (line.startsWith('0:')) { |
- timings.addAll(parseTimings(buildUri, line)); |
- } else { |
- parsingTimingBlock = false; |
- } |
- } |
- } |
- return new BuildResult(buildUri, failures, timings); |
-} |
- |
/// Generate a summary of the timeouts and other failures in [results]. |
String generateBuildResultsSummary( |
BuildUri buildUri, List<BuildResult> results) { |
@@ -177,130 +143,3 @@ String generateBuildResultsSummary( |
} |
return sb.toString(); |
} |
- |
-/// The results of a build step. |
-class BuildResult { |
- final BuildUri buildUri; |
- final List<TestFailure> _failures; |
- final List<Timing> _timings; |
- |
- BuildResult(this.buildUri, this._failures, this._timings); |
- |
- /// `true` of the build result has test failures. |
- bool get hasFailures => _failures.isNotEmpty; |
- |
- /// Returns the top-20 timings found in the build log. |
- Iterable<Timing> get timings => _timings; |
- |
- /// Returns the [TestFailure]s for tests that timed out. |
- Iterable<TestFailure> get timeouts { |
- return _failures |
- .where((TestFailure failure) => failure.actual == 'Timeout'); |
- } |
- |
- /// Returns the [TestFailure]s for failing tests that did not time out. |
- Iterable<TestFailure> get errors { |
- return _failures |
- .where((TestFailure failure) => failure.actual != 'Timeout'); |
- } |
- |
- String toString() { |
- StringBuffer sb = new StringBuffer(); |
- sb.write('$buildUri\n'); |
- sb.write('Failures:\n${_failures.join('\n-----\n')}\n'); |
- sb.write('\nTimings:\n${_timings.join('\n')}'); |
- return sb.toString(); |
- } |
-} |
- |
-/// Test failure data derived from the test failure summary in the build step |
-/// stdio log. |
-class TestFailure { |
- final BuildUri uri; |
- final TestConfiguration id; |
- final String expected; |
- final String actual; |
- final String text; |
- |
- factory TestFailure(BuildUri uri, List<String> lines) { |
- List<String> parts = split(lines.first, ['FAILED: ', ' ', ' ']); |
- String configName = parts[1]; |
- String archName = parts[2]; |
- String testName = parts[3]; |
- TestConfiguration id = |
- new TestConfiguration(configName, archName, testName); |
- String expected = split(lines[1], ['Expected: '])[1]; |
- String actual = split(lines[2], ['Actual: '])[1]; |
- return new TestFailure.internal( |
- uri, id, expected, actual, lines.skip(3).join('\n')); |
- } |
- |
- TestFailure.internal( |
- this.uri, this.id, this.expected, this.actual, this.text); |
- |
- String toString() { |
- StringBuffer sb = new StringBuffer(); |
- sb.write('FAILED: $id\n'); |
- sb.write('Expected: $expected\n'); |
- sb.write('Actual: $actual\n'); |
- sb.write(text); |
- return sb.toString(); |
- } |
-} |
- |
-/// Id for a single test step, for instance the compilation and run steps of |
-/// a test. |
-class TestStep { |
- final String stepName; |
- final TestConfiguration id; |
- |
- TestStep(this.stepName, this.id); |
- |
- String toString() { |
- return '$stepName - $id'; |
- } |
- |
- int get hashCode => stepName.hashCode * 13 + id.hashCode * 17; |
- |
- bool operator ==(other) { |
- if (identical(this, other)) return true; |
- if (other is! TestStep) return false; |
- return stepName == other.stepName && id == other.id; |
- } |
-} |
- |
-/// The timing result for a single test step. |
-class Timing { |
- final BuildUri uri; |
- final String time; |
- final TestStep step; |
- |
- Timing(this.uri, this.time, this.step); |
- |
- String toString() { |
- return '$time - $step'; |
- } |
-} |
- |
-/// Create the [Timing]s for the [line] as found in the top-20 timings of a |
-/// build step stdio log. |
-List<Timing> parseTimings(BuildUri uri, String line) { |
- List<String> parts = split(line, [' - ', ' - ', ' ']); |
- String time = parts[0]; |
- String stepName = parts[1]; |
- String configName = parts[2]; |
- String testNames = parts[3]; |
- List<Timing> timings = <Timing>[]; |
- for (String name in testNames.split(',')) { |
- name = name.trim(); |
- int slashPos = name.indexOf('/'); |
- String archName = name.substring(0, slashPos); |
- String testName = name.substring(slashPos + 1); |
- timings.add(new Timing( |
- uri, |
- time, |
- new TestStep( |
- stepName, new TestConfiguration(configName, archName, testName)))); |
- } |
- return timings; |
-} |