OLD | NEW |
(Empty) | |
| 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 |
| 3 // BSD-style license that can be found in the LICENSE file. |
| 4 |
| 5 /// Scans past dart2js-windows test steps for timeouts and reports the |
| 6 /// frequency of each test that has timed out. |
| 7 |
| 8 import 'dart:async'; |
| 9 import 'dart:io'; |
| 10 import 'package:args/args.dart'; |
| 11 import 'package:gardening/src/buildbot_data.dart'; |
| 12 import 'package:gardening/src/buildbot_loading.dart'; |
| 13 import 'package:gardening/src/buildbot_structures.dart'; |
| 14 import 'package:gardening/src/logdog.dart' as logdog; |
| 15 import 'package:gardening/src/util.dart'; |
| 16 |
| 17 main(List<String> args) async { |
| 18 ArgParser argParser = createArgParser(); |
| 19 argParser.addFlag('logdog', |
| 20 negatable: false, help: "Pull test results from logdog."); |
| 21 argParser.addOption('start', |
| 22 defaultsTo: '-2', |
| 23 help: "Start pulling from the specified <build-number>.\n" |
| 24 "Use negative numbers for the most recent builds;\n" |
| 25 "for instance -2 for the second-to-last build.'"); |
| 26 ArgResults argResults = argParser.parse(args); |
| 27 processArgResults(argResults); |
| 28 List<String> arguments = argResults.rest; |
| 29 if (arguments.length > 1) { |
| 30 print('Usage: find_timeouts.dart [options] [<count>]'); |
| 31 print('Where <count> is the number of old builds that are scanned'); |
| 32 print('and options are:'); |
| 33 print(argParser.usage); |
| 34 exit(1); |
| 35 } |
| 36 int buildNumberCount = 10; |
| 37 if (arguments.length > 0) { |
| 38 buildNumberCount = int.parse(arguments[0]); |
| 39 } |
| 40 int buildNumberOffset = int.parse(argResults['start']); |
| 41 |
| 42 bool useLogDog = argResults['logdog']; |
| 43 |
| 44 HttpClient client = new HttpClient(); |
| 45 BuildGroup group = |
| 46 buildGroups.firstWhere((g) => g.groupName == 'dart2js-windows'); |
| 47 Map<String, List<Timeout>> timeouts = <String, List<Timeout>>{}; |
| 48 for (BuildSubgroup subgroup in group.subgroups) { |
| 49 if (useLogDog) { |
| 50 await readLogDogResults(subgroup, timeouts, |
| 51 buildNumberOffset: buildNumberOffset, |
| 52 buildNumberCount: buildNumberCount); |
| 53 } else { |
| 54 await readBuildBotResults(client, subgroup, timeouts, |
| 55 buildNumberOffset: buildNumberOffset, |
| 56 buildNumberCount: buildNumberCount); |
| 57 } |
| 58 } |
| 59 |
| 60 List<String> sorted = timeouts.keys.toList() |
| 61 ..sort((a, b) { |
| 62 return -timeouts[a].length.compareTo(timeouts[b].length); |
| 63 }); |
| 64 |
| 65 sorted.forEach((String testName) { |
| 66 List<Timeout> list = timeouts[testName]; |
| 67 print('${padLeft('${list.length}', 4)} $testName'); |
| 68 for (Timeout timeout in list) { |
| 69 print(' - ${timeout.buildUri.botName}/${timeout.buildUri.stepName} ' |
| 70 '${timeout.timeout.id} (${timeout.buildNumber})'); |
| 71 } |
| 72 }); |
| 73 |
| 74 client.close(); |
| 75 } |
| 76 |
| 77 Future readLogDogResults( |
| 78 BuildSubgroup subgroup, Map<String, List<Timeout>> timeouts, |
| 79 {int buildNumberOffset, int buildNumberCount}) async { |
| 80 Map<String, String> subgroupPaths = subgroup.logDogPaths; |
| 81 for (String shardName in subgroupPaths.keys) { |
| 82 String subgroupPath = subgroupPaths[shardName]; |
| 83 List<int> buildNumbers = <int>[]; |
| 84 for (String line in logdog.ls(subgroupPath).split('\n')) { |
| 85 line = line.trim(); |
| 86 if (line.isNotEmpty) { |
| 87 buildNumbers.add(int.parse(line)); |
| 88 } |
| 89 } |
| 90 buildNumbers.sort((a, b) => -a.compareTo(b)); |
| 91 int buildNumberIndex; |
| 92 if (buildNumberOffset < 0) { |
| 93 buildNumberIndex = -buildNumberOffset - 1; |
| 94 } else { |
| 95 buildNumberIndex = buildNumbers.firstWhere((n) => n <= buildNumberOffset, |
| 96 orElse: () => buildNumbers.length); |
| 97 } |
| 98 for (int i = 0; i < buildNumberCount; i++) { |
| 99 if (buildNumberIndex + i < buildNumbers.length) { |
| 100 int buildNumber = buildNumbers[buildNumberIndex + i]; |
| 101 for (BuildUri buildUri |
| 102 in subgroup.createShardUris(shardName, buildNumber)) { |
| 103 BuildResult result = await readLogDogResult(buildUri); |
| 104 for (TestFailure timeout in result.timeouts) { |
| 105 timeouts.putIfAbsent(timeout.id.testName, () => <Timeout>[]).add( |
| 106 new Timeout(subgroup, result.buildNumber, buildUri, timeout)); |
| 107 } |
| 108 buildUri = buildUri.prev(); |
| 109 } |
| 110 } |
| 111 } |
| 112 } |
| 113 } |
| 114 |
| 115 Future readBuildBotResults(HttpClient client, BuildSubgroup subgroup, |
| 116 Map<String, List<Timeout>> timeouts, |
| 117 {int buildNumberOffset, int buildNumberCount}) async { |
| 118 List<BuildUri> buildUris = subgroup.createUris(buildNumberOffset); |
| 119 for (BuildUri buildUri in buildUris) { |
| 120 for (int i = 0; i < buildNumberCount; i++) { |
| 121 BuildResult result = await readBuildResult(client, buildUri); |
| 122 for (TestFailure timeout in result.timeouts) { |
| 123 timeouts |
| 124 .putIfAbsent(timeout.id.testName, () => <Timeout>[]) |
| 125 .add(new Timeout(subgroup, result.buildNumber, buildUri, timeout)); |
| 126 } |
| 127 buildUri = result.buildUri.prev(); |
| 128 } |
| 129 } |
| 130 } |
| 131 |
| 132 class Timeout { |
| 133 final BuildSubgroup subgroup; |
| 134 final int buildNumber; |
| 135 final BuildUri buildUri; |
| 136 final TestFailure timeout; |
| 137 |
| 138 Timeout(this.subgroup, this.buildNumber, this.buildUri, this.timeout); |
| 139 } |
OLD | NEW |