OLD | NEW |
1 // Copyright (c) 2017, the Dart project authors. Please see the AUTHORS file | 1 // Copyright (c) 2017, the Dart project authors. Please see the AUTHORS file |
2 // for details. All rights reserved. Use of this source code is governed by a | 2 // for details. All rights reserved. Use of this source code is governed by a |
3 // BSD-style license that can be found in the LICENSE file. | 3 // BSD-style license that can be found in the LICENSE file. |
4 | 4 |
5 /// Compares the test log of a build step with previous builds. | 5 /// Compares the test log of a build step with previous builds. |
6 /// | 6 /// |
7 /// Use this to detect flakiness of failures, especially timeouts. | 7 /// Use this to detect flakiness of failures, especially timeouts. |
8 | 8 |
9 import 'dart:async'; | 9 import 'dart:async'; |
10 import 'dart:io'; | |
11 | 10 |
12 import 'package:args/args.dart'; | |
13 import 'package:gardening/src/buildbot_structures.dart'; | 11 import 'package:gardening/src/buildbot_structures.dart'; |
| 12 import 'package:gardening/src/buildbot_data.dart'; |
14 import 'package:gardening/src/client.dart'; | 13 import 'package:gardening/src/client.dart'; |
15 import 'package:gardening/src/util.dart'; | 14 import 'package:gardening/src/util.dart'; |
16 | 15 |
17 void help(ArgParser argParser) { | 16 Future mainInternal(BuildbotClient client, List<String> args, |
18 print('Given a <log-uri> finds all failing tests in that stdout. Then '); | 17 {int runCount: 10}) async { |
19 print('fetches earlier runs of the same bot and compares the results.'); | 18 printBuildResultsSummary( |
20 print('This tool is particularly useful to detect flakes and their '); | 19 await loadBuildResults(client, args, runCount: runCount)); |
21 print('frequency.'); | |
22 print('Usage: compare_failures [options] <log-uri>'); | |
23 print('where <log-uri> is the uri the stdio output of a failing test step'); | |
24 print('and options are:'); | |
25 print(argParser.usage); | |
26 } | 20 } |
27 | 21 |
28 main(List<String> args) async { | 22 /// Loads [BuildResult]s for the [runCount] last builds for the build(s) in |
29 ArgParser argParser = createArgParser(); | 23 /// [args]. [args] can be a list of [BuildGroup] names or a list of log uris. |
30 argParser.addOption("run-count", | 24 Future<Map<BuildUri, List<BuildResult>>> loadBuildResults( |
31 defaultsTo: "10", help: "How many previous runs should be fetched"); | 25 BuildbotClient client, List<String> args, |
32 ArgResults argResults = argParser.parse(args); | 26 {int runCount: 10}) async { |
33 processArgResults(argResults); | 27 List<BuildUri> buildUriList = <BuildUri>[]; |
| 28 for (BuildGroup buildGroup in buildGroups) { |
| 29 if (args.contains(buildGroup.groupName)) { |
| 30 buildUriList.addAll(buildGroup.createUris(client.mostRecentBuildNumber)); |
| 31 } |
| 32 } |
| 33 if (buildUriList.isEmpty) { |
| 34 for (String url in args) { |
| 35 if (!url.endsWith('/text')) { |
| 36 // Use the text version of the stdio log. |
| 37 url += '/text'; |
| 38 } |
| 39 Uri uri = Uri.parse(url); |
| 40 BuildUri buildUri = new BuildUri(uri); |
| 41 buildUriList.add(buildUri); |
| 42 } |
| 43 } |
| 44 Map<BuildUri, List<BuildResult>> buildResults = |
| 45 <BuildUri, List<BuildResult>>{}; |
| 46 for (BuildUri buildUri in buildUriList) { |
| 47 List<BuildResult> results = |
| 48 await readBuildResults(client, buildUri, runCount); |
| 49 buildResults[buildUri] = results; |
| 50 } |
| 51 return buildResults; |
| 52 } |
34 | 53 |
35 BuildbotClient client = argResults['logdog'] | 54 /// Prints summaries for the [buildResults]. |
36 ? new LogdogBuildbotClient() | 55 // TODO(johnniwinther): Improve printing of multiple [BuildUri] results. |
37 : new HttpBuildbotClient(); | 56 void printBuildResultsSummary(Map<BuildUri, List<BuildResult>> buildResults) { |
38 | 57 buildResults.forEach((BuildUri buildUri, List<BuildResult> results) { |
39 var runCount = int.parse(argResults['run-count'], onError: (_) => null); | 58 print(generateBuildResultsSummary(buildUri, results)); |
40 | 59 }); |
41 if (argResults.rest.length != 1 || argResults['help'] || runCount == null) { | |
42 help(argParser); | |
43 if (argResults['help']) return; | |
44 exit(1); | |
45 } | |
46 String url = argResults.rest.first; | |
47 if (!url.endsWith('/text')) { | |
48 // Use the text version of the stdio log. | |
49 url += '/text'; | |
50 } | |
51 Uri uri = Uri.parse(url); | |
52 BuildUri buildUri = new BuildUri(uri); | |
53 List<BuildResult> results = | |
54 await readBuildResults(client, buildUri, runCount); | |
55 print(generateBuildResultsSummary(buildUri, results)); | |
56 client.close(); | |
57 } | 60 } |
58 | 61 |
59 /// Creates a [BuildResult] for [buildUri] and, if it contains failures, the | 62 /// Creates a [BuildResult] for [buildUri] and, if it contains failures, the |
60 /// [BuildResult]s for the previous [runCount] builds. | 63 /// [BuildResult]s for the previous [runCount] builds. |
61 Future<List<BuildResult>> readBuildResults( | 64 Future<List<BuildResult>> readBuildResults( |
62 BuildbotClient client, BuildUri buildUri, int runCount) async { | 65 BuildbotClient client, BuildUri buildUri, int runCount) async { |
63 List<BuildResult> summaries = <BuildResult>[]; | 66 List<BuildResult> summaries = <BuildResult>[]; |
64 BuildResult summary = await client.readResult(buildUri); | 67 BuildResult summary = await client.readResult(buildUri); |
65 summaries.add(summary); | 68 summaries.add(summary); |
66 if (summary.hasFailures) { | 69 if (summary.hasFailures) { |
(...skipping 80 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
147 } else { | 150 } else { |
148 sb.write(' ' * 10); | 151 sb.write(' ' * 10); |
149 sb.write(' / '); | 152 sb.write(' / '); |
150 sb.write(padRight('-- OK --', 10)); | 153 sb.write(padRight('-- OK --', 10)); |
151 } | 154 } |
152 sb.write('\n'); | 155 sb.write('\n'); |
153 } | 156 } |
154 sb.write('\n'); | 157 sb.write('\n'); |
155 }); | 158 }); |
156 } | 159 } |
| 160 if (timeoutIds.isEmpty && errorIds.isEmpty) { |
| 161 sb.write('No errors found.'); |
| 162 } |
157 return sb.toString(); | 163 return sb.toString(); |
158 } | 164 } |
OLD | NEW |