| OLD | NEW |
| 1 #!/usr/bin/env python | 1 #!/usr/bin/env python |
| 2 # Copyright 2014 The Chromium Authors. All rights reserved. | 2 # Copyright 2014 The Chromium Authors. All rights reserved. |
| 3 # Use of this source code is governed by a BSD-style license that can be | 3 # Use of this source code is governed by a BSD-style license that can be |
| 4 # found in the LICENSE file. | 4 # found in the LICENSE file. |
| 5 | 5 |
| 6 import argparse | 6 import argparse |
| 7 import json | 7 import json |
| 8 import os | 8 import os |
| 9 import subprocess | 9 import subprocess |
| 10 import sys | 10 import sys |
| (...skipping 68 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
| 79 'iOS_Simulator_(dbg)', | 79 'iOS_Simulator_(dbg)', |
| 80 ], | 80 ], |
| 81 'master.chromium.memory': [ | 81 'master.chromium.memory': [ |
| 82 'Linux ASan Tests (sandboxed)', | 82 'Linux ASan Tests (sandboxed)', |
| 83 ], | 83 ], |
| 84 'master.chromium.win': [ | 84 'master.chromium.win': [ |
| 85 'Win x64 Builder (dbg)', | 85 'Win x64 Builder (dbg)', |
| 86 ], | 86 ], |
| 87 } | 87 } |
| 88 | 88 |
| 89 # TODO(kbr): remove these suppressions. They're only needed |
| 90 # temporarily during the transition of the chromium.gpu bots to the |
| 91 # Chromium recipe, in order to achieve full code coverage while the |
| 92 # bots are actually running a different recipe. |
| 93 BOGUS_BUILDER_SUPPRESSIONS = [ |
| 94 "GPU Fake Linux Builder", |
| 95 "Fake Linux Release (NVIDIA)" |
| 96 ] |
| 97 |
| 98 WRONG_RECIPE_SUPPRESSIONS = [ |
| 99 "GPU Fake Linux Builder", |
| 100 "Fake Linux Release (NVIDIA)" |
| 101 ] |
| 102 |
| 89 | 103 |
| 90 def getBuilders(recipe_name): | 104 def getBuilders(recipe_name): |
| 91 """Asks the given recipe to dump its BUILDERS dictionary. | 105 """Asks the given recipe to dump its BUILDERS dictionary. |
| 92 | 106 |
| 93 This must be implemented by the recipe in question. | 107 This must be implemented by the recipe in question. |
| 94 """ | 108 """ |
| 95 (fh, builders_file) = tempfile.mkstemp('.json') | 109 (fh, builders_file) = tempfile.mkstemp('.json') |
| 96 os.close(fh) | 110 os.close(fh) |
| 97 try: | 111 try: |
| 98 subprocess.check_call([ | 112 subprocess.check_call([ |
| (...skipping 56 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
| 155 | 169 |
| 156 # We only have a standardized way to mirror builders using the chromium | 170 # We only have a standardized way to mirror builders using the chromium |
| 157 # recipe on the tryserver. | 171 # recipe on the tryserver. |
| 158 chromium_recipe_builders[master] = [b for b in builders | 172 chromium_recipe_builders[master] = [b for b in builders |
| 159 if builders[b] == 'chromium'] | 173 if builders[b] == 'chromium'] |
| 160 | 174 |
| 161 recipe_side_builders = chromium_BUILDERS.get( | 175 recipe_side_builders = chromium_BUILDERS.get( |
| 162 master.replace('master.', ''), {}).get('builders') | 176 master.replace('master.', ''), {}).get('builders') |
| 163 if recipe_side_builders is not None: | 177 if recipe_side_builders is not None: |
| 164 bogus_builders = set(recipe_side_builders.keys()).difference( | 178 bogus_builders = set(recipe_side_builders.keys()).difference( |
| 165 set(builders.keys())) | 179 set(builders.keys())).difference(set(BOGUS_BUILDER_SUPPRESSIONS)) |
| 166 if bogus_builders: | 180 if bogus_builders: |
| 167 exit_code = 1 | 181 exit_code = 1 |
| 168 print 'The following builders from chromium recipe' | 182 print 'The following builders from chromium recipe' |
| 169 print 'do not exist in master config for %s:' % master | 183 print 'do not exist in master config for %s:' % master |
| 170 print '\n'.join('\t%s' % b for b in sorted(bogus_builders)) | 184 print '\n'.join('\t%s' % b for b in sorted(bogus_builders)) |
| 171 | 185 |
| 172 other_recipe_builders = set(recipe_side_builders.keys()).difference( | 186 other_recipe_builders = set(recipe_side_builders.keys()).difference( |
| 173 set(chromium_recipe_builders[master])) | 187 set(chromium_recipe_builders[master])).difference( |
| 188 set(WRONG_RECIPE_SUPPRESSIONS)) |
| 174 if other_recipe_builders: | 189 if other_recipe_builders: |
| 175 exit_code = 1 | 190 exit_code = 1 |
| 176 print 'The following builders from chromium recipe' | 191 print 'The following builders from chromium recipe' |
| 177 print 'are configured to run a different recipe on the master' | 192 print 'are configured to run a different recipe on the master' |
| 178 print '(%s):' % master | 193 print '(%s):' % master |
| 179 print '\n'.join('\t%s' % b for b in sorted(other_recipe_builders)) | 194 print '\n'.join('\t%s' % b for b in sorted(other_recipe_builders)) |
| 180 | 195 |
| 181 | 196 |
| 182 for master in TRYSERVER_MASTERS: | 197 for master in TRYSERVER_MASTERS: |
| 183 short_master = master.replace('master.', '') | 198 short_master = master.replace('master.', '') |
| 184 builders = getBuildersAndRecipes(master) | 199 builders = getBuildersAndRecipes(master) |
| 185 recipe_side_builders = chromium_trybot_BUILDERS[ | 200 recipe_side_builders = chromium_trybot_BUILDERS[ |
| 186 short_master]['builders'] | 201 short_master]['builders'] |
| 187 | 202 |
| 188 bogus_builders = set(recipe_side_builders.keys()).difference( | 203 bogus_builders = set(recipe_side_builders.keys()).difference( |
| 189 set(builders.keys())) | 204 set(builders.keys())) |
| 190 if bogus_builders: | 205 if bogus_builders: |
| 191 exit_code = 1 | 206 exit_code = 1 |
| 192 print 'The following builders from chromium_trybot recipe' | 207 print 'The following builders from chromium_trybot recipe' |
| 193 print 'do not exist in master config for %s:' % master | 208 print 'do not exist in master config for %s:' % master |
| 194 print '\n'.join('\t%s' % b for b in sorted(bogus_builders)) | 209 print '\n'.join('\t%s' % b for b in sorted(bogus_builders)) |
| 195 | 210 |
| 196 for builder, recipe in builders.iteritems(): | 211 for builder, recipe in builders.iteritems(): |
| 197 # Only the chromium_trybot recipe knows how to mirror a main waterfall | 212 # Only the chromium_trybot recipe knows how to mirror a main waterfall |
| 198 # builder. | 213 # builder. |
| 199 if recipe != 'chromium_trybot': | 214 if recipe != 'chromium_trybot': |
| 200 continue | 215 continue |
| 201 | 216 |
| 202 bot_config = recipe_side_builders.get(builder) | 217 bot_configs = recipe_side_builders.get(builder) |
| 203 if not bot_config: | 218 if not bot_configs: |
| 204 continue | 219 continue |
| 205 | 220 |
| 221 # Support trybots which mirror more than one waterfall bot. |
| 222 # This is identical code to api.chromium_tests.normalize_bot_desc. |
| 223 if not isinstance(bot_configs, (list, tuple)): |
| 224 bot_configs = [bot_configs] |
| 225 |
| 206 if args.cq_config and builder not in cq_builders.get(short_master, {}): | 226 if args.cq_config and builder not in cq_builders.get(short_master, {}): |
| 207 continue | 227 continue |
| 208 | 228 |
| 209 # TODO(phajdan.jr): Make it an error if any builders referenced here | 229 # TODO(phajdan.jr): Make it an error if any builders referenced here |
| 210 # are not using chromium recipe. | 230 # are not using chromium recipe. |
| 211 main_waterfall_master = 'master.' + bot_config['mastername'] | 231 for bot_config in bot_configs: |
| 212 bots = [bot_config['buildername']] | 232 main_waterfall_master = 'master.' + bot_config['mastername'] |
| 213 if bot_config.get('tester'): | 233 bots = [bot_config['buildername']] |
| 214 bots.append(bot_config['tester']) | 234 if bot_config.get('tester'): |
| 215 for mw_builder in bots: | 235 bots.append(bot_config['tester']) |
| 216 if mw_builder in chromium_recipe_builders.get( | 236 for mw_builder in bots: |
| 217 main_waterfall_master, []): | 237 if mw_builder in chromium_recipe_builders.get( |
| 218 covered_builders.add((main_waterfall_master, mw_builder)) | 238 main_waterfall_master, []): |
| 239 covered_builders.add((main_waterfall_master, mw_builder)) |
| 219 | 240 |
| 220 # TODO(phajdan.jr): Add a way to only count trybots launched by CQ by default. | 241 # TODO(phajdan.jr): Add a way to only count trybots launched by CQ by default. |
| 221 print 'Main waterfall ng-trybot coverage: %.2f' % ( | 242 print 'Main waterfall ng-trybot coverage: %.2f' % ( |
| 222 100.0 * len(covered_builders) / len(all_builders)) | 243 100.0 * len(covered_builders) / len(all_builders)) |
| 223 | 244 |
| 224 not_covered_builders = all_builders.difference(covered_builders) | 245 not_covered_builders = all_builders.difference(covered_builders) |
| 225 suppressed_builders = set() | 246 suppressed_builders = set() |
| 226 for master, builders in SUPPRESSIONS.iteritems(): | 247 for master, builders in SUPPRESSIONS.iteritems(): |
| 227 suppressed_builders.update((master, b) for b in builders) | 248 suppressed_builders.update((master, b) for b in builders) |
| 228 | 249 |
| 229 regressed_builders = not_covered_builders.difference(suppressed_builders) | 250 regressed_builders = not_covered_builders.difference(suppressed_builders) |
| 230 if regressed_builders: | 251 if regressed_builders: |
| 231 exit_code = 1 | 252 exit_code = 1 |
| 232 print 'Regression, the following builders lack in-sync tryserver coverage:' | 253 print 'Regression, the following builders lack in-sync tryserver coverage:' |
| 233 print '\n'.join(sorted( | 254 print '\n'.join(sorted( |
| 234 '\t%s:%s' % (b[0], b[1]) for b in regressed_builders)) | 255 '\t%s:%s' % (b[0], b[1]) for b in regressed_builders)) |
| 235 | 256 |
| 236 unused_suppressions = suppressed_builders.difference(not_covered_builders) | 257 unused_suppressions = suppressed_builders.difference(not_covered_builders) |
| 237 if unused_suppressions: | 258 if unused_suppressions: |
| 238 exit_code = 1 | 259 exit_code = 1 |
| 239 print 'Unused suppressions:' | 260 print 'Unused suppressions:' |
| 240 print '\n'.join(sorted( | 261 print '\n'.join(sorted( |
| 241 '\t%s:%s' % (b[0], b[1]) for b in unused_suppressions)) | 262 '\t%s:%s' % (b[0], b[1]) for b in unused_suppressions)) |
| 242 | 263 |
| 243 return exit_code | 264 return exit_code |
| 244 | 265 |
| 245 | 266 |
| 246 if __name__ == '__main__': | 267 if __name__ == '__main__': |
| 247 sys.exit(main(sys.argv[1:])) | 268 sys.exit(main(sys.argv[1:])) |
| OLD | NEW |