Chromium Code Reviews
chromiumcodereview-hr@appspot.gserviceaccount.com (chromiumcodereview-hr) | Please choose your nickname with Settings | Help | Chromium Project | Gerrit Changes | Sign out
(167)

Side by Side Diff: tools/gardening/lib/compare_failures.dart

Issue 2753513005: Add status_summary and current_summary to tools/gardening (Closed)
Patch Set: dartfmt Created 3 years, 9 months ago
Use n/p to move between diff chunks; N/P to move between comments. Draft comments are only viewable by you.
Jump to:
View unified diff | Download patch
OLDNEW
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:convert'; 10 import 'dart:convert';
11 import 'dart:io'; 11 import 'dart:io';
12 12
13 import 'src/buildbot_structures.dart';
14 import 'src/util.dart';
15
13 main(List<String> args) async { 16 main(List<String> args) async {
14 if (args.length != 1) { 17 if (args.length != 1) {
15 print('Usage: compare_failures <log-uri>'); 18 print('Usage: compare_failures <log-uri>');
16 exit(1); 19 exit(1);
17 } 20 }
18 String url = args.first; 21 String url = args.first;
19 if (!url.endsWith('/text')) { 22 if (!url.endsWith('/text')) {
20 // Use the text version of the stdio log. 23 // Use the text version of the stdio log.
21 url += '/text'; 24 url += '/text';
22 } 25 }
23 Uri uri = Uri.parse(url); 26 Uri uri = Uri.parse(url);
24 HttpClient client = new HttpClient(); 27 HttpClient client = new HttpClient();
25 BuildUri buildUri = new BuildUri(uri); 28 BuildUri buildUri = new BuildUri(uri);
26 List<BuildResult> results = await readBuildResults(client, buildUri); 29 List<BuildResult> results = await readBuildResults(client, buildUri);
27 print(generateBuildResultsSummary(buildUri, results)); 30 print(generateBuildResultsSummary(buildUri, results));
28 client.close(); 31 client.close();
29 } 32 }
30 33
31 /// Creates a [BuildResult] for [buildUri] and, if it contains failures, the 34 /// Creates a [BuildResult] for [buildUri] and, if it contains failures, the
32 /// [BuildResult]s for the previous 5 builds. 35 /// [BuildResult]s for the previous 5 builds.
33 Future<List<BuildResult>> readBuildResults( 36 Future<List<BuildResult>> readBuildResults(
34 HttpClient client, BuildUri buildUri) async { 37 HttpClient client, BuildUri buildUri) async {
35 List<BuildResult> summaries = <BuildResult>[]; 38 List<BuildResult> summaries = <BuildResult>[];
36 BuildResult firstSummary = await readBuildResult(client, buildUri); 39 BuildResult firstSummary = await readBuildResult(client, buildUri);
37 summaries.add(firstSummary); 40 summaries.add(firstSummary);
38 if (firstSummary.hasFailures) { 41 if (firstSummary.hasFailures) {
39 for (int i = 0; i < 5; i++) { 42 for (int i = 0; i < 10; i++) {
40 buildUri = buildUri.prev(); 43 buildUri = buildUri.prev();
41 summaries.add(await readBuildResult(client, buildUri)); 44 summaries.add(await readBuildResult(client, buildUri));
42 } 45 }
43 } 46 }
44 return summaries; 47 return summaries;
45 } 48 }
46 49
47 /// Reads the content of [uri] as text. 50 /// Reads the content of [uri] as text.
48 Future<String> readUriAsText(HttpClient client, Uri uri) async { 51 Future<String> readUriAsText(HttpClient client, Uri uri) async {
49 HttpClientRequest request = await client.getUrl(uri); 52 HttpClientRequest request = await client.getUrl(uri);
(...skipping 161 matching lines...) Expand 10 before | Expand all | Expand 10 after
211 214
212 String toString() { 215 String toString() {
213 StringBuffer sb = new StringBuffer(); 216 StringBuffer sb = new StringBuffer();
214 sb.write('$buildUri\n'); 217 sb.write('$buildUri\n');
215 sb.write('Failures:\n${_failures.join('\n-----\n')}\n'); 218 sb.write('Failures:\n${_failures.join('\n-----\n')}\n');
216 sb.write('\nTimings:\n${_timings.join('\n')}'); 219 sb.write('\nTimings:\n${_timings.join('\n')}');
217 return sb.toString(); 220 return sb.toString();
218 } 221 }
219 } 222 }
220 223
221 /// The [Uri] of a build step stdio log split into its subparts.
222 class BuildUri {
223 final String scheme;
224 final String host;
225 final String prefix;
226 final String botName;
227 final int buildNumber;
228 final String stepName;
229 final String suffix;
230
231 factory BuildUri(Uri uri) {
232 String scheme = uri.scheme;
233 String host = uri.host;
234 List<String> parts =
235 split(uri.path, ['/builders/', '/builds/', '/steps/', '/logs/']);
236 String prefix = parts[0];
237 String botName = parts[1];
238 int buildNumber = int.parse(parts[2]);
239 String stepName = parts[3];
240 String suffix = parts[4];
241 return new BuildUri.internal(
242 scheme, host, prefix, botName, buildNumber, stepName, suffix);
243 }
244
245 BuildUri.internal(this.scheme, this.host, this.prefix, this.botName,
246 this.buildNumber, this.stepName, this.suffix);
247
248 String get buildName =>
249 '/builders/$botName/builds/$buildNumber/steps/$stepName';
250
251 String get path => '$prefix$buildName/logs/$suffix';
252
253 /// Creates the [Uri] for this build step stdio log.
254 Uri toUri() {
255 return new Uri(scheme: scheme, host: host, path: path);
256 }
257
258 /// Returns the [BuildUri] the previous build of this build step.
259 BuildUri prev() {
260 return new BuildUri.internal(
261 scheme, host, prefix, botName, buildNumber - 1, stepName, suffix);
262 }
263
264 String toString() {
265 return buildName;
266 }
267 }
268
269 /// Id for a test on a specific configuration, for instance
270 /// `dart2js-chrome release_x64/co19/Language/Metadata/before_function_t07`.
271 class TestConfiguration {
272 final String configName;
273 final String testName;
274
275 TestConfiguration(this.configName, this.testName);
276
277 String toString() {
278 return '$configName $testName';
279 }
280
281 int get hashCode => configName.hashCode * 17 + testName.hashCode * 19;
282
283 bool operator ==(other) {
284 if (identical(this, other)) return true;
285 if (other is! TestConfiguration) return false;
286 return configName == other.configName && testName == other.testName;
287 }
288 }
289
290 /// Test failure data derived from the test failure summary in the build step 224 /// Test failure data derived from the test failure summary in the build step
291 /// stdio log. 225 /// stdio log.
292 class TestFailure { 226 class TestFailure {
293 final BuildUri uri; 227 final BuildUri uri;
294 final TestConfiguration id; 228 final TestConfiguration id;
295 final String expected; 229 final String expected;
296 final String actual; 230 final String actual;
297 final String text; 231 final String text;
298 232
299 factory TestFailure(BuildUri uri, List<String> lines) { 233 factory TestFailure(BuildUri uri, List<String> lines) {
300 List<String> parts = split(lines.first, ['FAILED: ', ' ', ' ']); 234 List<String> parts = split(lines.first, ['FAILED: ', ' ', ' ']);
301 String configName = parts[1]; 235 String configName = parts[1];
302 String archName = parts[2]; 236 String archName = parts[2];
303 String testName = parts[3]; 237 String testName = parts[3];
304 TestConfiguration id = 238 TestConfiguration id =
305 new TestConfiguration(configName, '$archName/$testName'); 239 new TestConfiguration(configName, archName, testName);
306 String expected = split(lines[1], ['Expected: '])[1]; 240 String expected = split(lines[1], ['Expected: '])[1];
307 String actual = split(lines[2], ['Actual: '])[1]; 241 String actual = split(lines[2], ['Actual: '])[1];
308 return new TestFailure.internal( 242 return new TestFailure.internal(
309 uri, id, expected, actual, lines.skip(3).join('\n')); 243 uri, id, expected, actual, lines.skip(3).join('\n'));
310 } 244 }
311 245
312 TestFailure.internal( 246 TestFailure.internal(
313 this.uri, this.id, this.expected, this.actual, this.text); 247 this.uri, this.id, this.expected, this.actual, this.text);
314 248
315 String toString() { 249 String toString() {
(...skipping 42 matching lines...) Expand 10 before | Expand all | Expand 10 after
358 292
359 /// Create the [Timing]s for the [line] as found in the top-20 timings of a 293 /// Create the [Timing]s for the [line] as found in the top-20 timings of a
360 /// build step stdio log. 294 /// build step stdio log.
361 List<Timing> parseTimings(BuildUri uri, String line) { 295 List<Timing> parseTimings(BuildUri uri, String line) {
362 List<String> parts = split(line, [' - ', ' - ', ' ']); 296 List<String> parts = split(line, [' - ', ' - ', ' ']);
363 String time = parts[0]; 297 String time = parts[0];
364 String stepName = parts[1]; 298 String stepName = parts[1];
365 String configName = parts[2]; 299 String configName = parts[2];
366 String testNames = parts[3]; 300 String testNames = parts[3];
367 List<Timing> timings = <Timing>[]; 301 List<Timing> timings = <Timing>[];
368 for (String testName in testNames.split(',')) { 302 for (String name in testNames.split(',')) {
303 name = name.trim();
304 int slashPos = name.indexOf('/');
305 String archName = name.substring(0, slashPos);
306 String testName = name.substring(slashPos + 1);
369 timings.add(new Timing( 307 timings.add(new Timing(
370 uri, 308 uri,
371 time, 309 time,
372 new TestStep( 310 new TestStep(
373 stepName, new TestConfiguration(configName, testName.trim())))); 311 stepName, new TestConfiguration(configName, archName, testName))));
374 } 312 }
375 return timings; 313 return timings;
376 } 314 }
377
378 /// Split [text] using [infixes] as infix markers.
379 List<String> split(String text, List<String> infixes) {
380 List<String> result = <String>[];
381 int start = 0;
382 for (String infix in infixes) {
383 int index = text.indexOf(infix, start);
384 if (index == -1)
385 throw "'$infix' not found in '$text' from offset ${start}.";
386 result.add(text.substring(start, index));
387 start = index + infix.length;
388 }
389 result.add(text.substring(start));
390 return result;
391 }
392
393 /// Pad [text] with spaces to the right to fit [length].
394 String padRight(String text, int length) {
395 if (text.length < length) return '${text}${' ' * (length - text.length)}';
396 return text;
397 }
398
399 void log(String text) {
400 print(text);
401 }
OLDNEW

Powered by Google App Engine
This is Rietveld 408576698