Chromium Code Reviews| OLD | NEW |
|---|---|
| 1 # Copyright 2015 The Chromium Authors. All rights reserved. | 1 # Copyright 2015 The Chromium Authors. All rights reserved. |
| 2 # Use of this source code is governed by a BSD-style license that can be | 2 # Use of this source code is governed by a BSD-style license that can be |
| 3 # found in the LICENSE file. | 3 # found in the LICENSE file. |
| 4 | 4 |
| 5 from collections import defaultdict | |
| 5 import json | 6 import json |
| 6 | 7 |
| 7 from recipe_engine.config import Dict | 8 from recipe_engine.config import Dict |
| 9 from recipe_engine.config import List | |
| 8 from recipe_engine.config import Single | 10 from recipe_engine.config import Single |
| 9 from recipe_engine.recipe_api import Property | 11 from recipe_engine.recipe_api import Property |
| 10 | 12 |
| 11 | 13 |
| 12 DEPS = [ | 14 DEPS = [ |
| 13 'adb', | 15 'adb', |
| 14 'depot_tools/bot_update', | 16 'depot_tools/bot_update', |
| 15 'chromium', | 17 'chromium', |
| 16 'chromium_android', | 18 'chromium_android', |
| 17 'chromium_tests', | 19 'chromium_tests', |
| (...skipping 28 matching lines...) Expand all Loading... | |
| 46 'tests': Property( | 48 'tests': Property( |
| 47 kind=Dict(value_type=list), | 49 kind=Dict(value_type=list), |
| 48 help='The failed tests, the test name should be full name, e.g.: {' | 50 help='The failed tests, the test name should be full name, e.g.: {' |
| 49 ' "browser_tests": [' | 51 ' "browser_tests": [' |
| 50 ' "suite.test1", "suite.test2"' | 52 ' "suite.test1", "suite.test2"' |
| 51 ' ]' | 53 ' ]' |
| 52 '}'), | 54 '}'), |
| 53 'use_analyze': Property( | 55 'use_analyze': Property( |
| 54 kind=Single(bool, empty_val=False, required=False), default=True, | 56 kind=Single(bool, empty_val=False, required=False), default=True, |
| 55 help='Use analyze to skip commits that do not affect tests.'), | 57 help='Use analyze to skip commits that do not affect tests.'), |
| 58 'suspected_revisions': Property( | |
| 59 kind=List(basestring), default=[], | |
| 60 help='A list of suspected revisions from heuristic analysis.'), | |
| 56 } | 61 } |
| 57 | 62 |
| 58 | 63 |
| 59 class TestResult(object): | 64 class TestResult(object): |
| 60 SKIPPED = 'skipped' # A commit doesn't impact the test. | 65 SKIPPED = 'skipped' # A commit doesn't impact the test. |
| 61 PASSED = 'passed' # The compile or test passed. | 66 PASSED = 'passed' # The compile or test passed. |
| 62 FAILED = 'failed' # The compile or test failed. | 67 FAILED = 'failed' # The compile or test failed. |
| 63 | 68 |
| 64 | 69 |
| 65 def _compile_and_test_at_revision(api, target_mastername, target_buildername, | 70 def _compile_and_test_at_revision(api, target_mastername, target_buildername, |
| (...skipping 53 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... | |
| 119 bot_config, | 124 bot_config, |
| 120 bot_update_step, | 125 bot_update_step, |
| 121 bot_db, | 126 bot_db, |
| 122 actual_compile_targets, | 127 actual_compile_targets, |
| 123 tests_including_triggered=actual_tests_to_run, | 128 tests_including_triggered=actual_tests_to_run, |
| 124 mb_mastername=target_mastername, | 129 mb_mastername=target_mastername, |
| 125 mb_buildername=target_buildername, | 130 mb_buildername=target_buildername, |
| 126 override_bot_type='builder_tester') | 131 override_bot_type='builder_tester') |
| 127 | 132 |
| 128 # Run the tests. | 133 # Run the tests. |
| 134 failed_tests_dict = defaultdict(list) | |
| 129 with api.chromium_tests.wrap_chromium_tests( | 135 with api.chromium_tests.wrap_chromium_tests( |
| 130 bot_config, actual_tests_to_run): | 136 bot_config, actual_tests_to_run): |
| 131 failed_tests = api.test_utils.run_tests( | 137 failed_tests = api.test_utils.run_tests( |
| 132 api, actual_tests_to_run, | 138 api, actual_tests_to_run, |
| 133 suffix=revision, test_filters=requested_tests) | 139 suffix=revision, test_filters=requested_tests) |
| 134 | 140 |
| 135 # Process failed tests. | 141 # Process failed tests. |
| 136 for failed_test in failed_tests: | 142 for failed_test in failed_tests: |
| 137 valid = failed_test.has_valid_results(api, suffix=revision) | 143 valid = failed_test.has_valid_results(api, suffix=revision) |
| 138 results[failed_test.name] = { | 144 results[failed_test.name] = { |
| 139 'status': TestResult.FAILED, | 145 'status': TestResult.FAILED, |
| 140 'valid': valid, | 146 'valid': valid, |
| 141 } | 147 } |
| 142 if valid: | 148 if valid: |
| 143 results[failed_test.name]['failures'] = list( | 149 test_list = list(failed_test.failures(api, suffix=revision)) |
| 144 failed_test.failures(api, suffix=revision)) | 150 results[failed_test.name]['failures'] = test_list |
| 151 failed_tests_dict[failed_test.name].extend(test_list) | |
| 145 | 152 |
| 146 # Process passed tests. | 153 # Process passed tests. |
| 147 for test in actual_tests_to_run: | 154 for test in actual_tests_to_run: |
| 148 if test not in failed_tests: | 155 if test not in failed_tests: |
| 149 results[test.name] = { | 156 results[test.name] = { |
| 150 'status': TestResult.PASSED, | 157 'status': TestResult.PASSED, |
| 151 'valid': True, | 158 'valid': True, |
| 152 } | 159 } |
| 153 | 160 |
| 154 # Process skipped tests in two scenarios: | 161 # Process skipped tests in two scenarios: |
| 155 # 1. Skipped by "analyze": tests are not affected by the given revision. | 162 # 1. Skipped by "analyze": tests are not affected by the given revision. |
| 156 # 2. Skipped because the requested tests don't exist at the given revision. | 163 # 2. Skipped because the requested tests don't exist at the given revision. |
| 157 for test_name in requested_tests.keys(): | 164 for test_name in requested_tests.keys(): |
| 158 if test_name not in results: | 165 if test_name not in results: |
| 159 results[test_name] = { | 166 results[test_name] = { |
| 160 'status': TestResult.SKIPPED, | 167 'status': TestResult.SKIPPED, |
| 161 'valid': True, | 168 'valid': True, |
| 162 } | 169 } |
| 163 | 170 |
| 164 return results | 171 return results, failed_tests_dict |
| 165 | 172 |
| 166 | 173 |
| 167 def RunSteps(api, target_mastername, target_testername, | 174 def _get_shrinked_test_dict(original_test_dict, failed_tests_dict): |
|
lijeffrey
2016/05/03 23:25:44
'shrinked' sounds a bit strange, how about rename
chanli
2016/05/04 17:14:40
It's actually not 'unique'... What I do here is ju
| |
| 168 good_revision, bad_revision, tests, use_analyze): | 175 # Remove tests that are in both dicts from the original test dict. |
| 176 if not failed_tests_dict: | |
| 177 return original_test_dict | |
| 178 shrinked_dict = defaultdict(list) | |
| 179 for step, tests in original_test_dict.iteritems(): | |
| 180 if step in failed_tests_dict: | |
| 181 for test in tests: | |
| 182 if test not in failed_tests_dict[step]: | |
| 183 shrinked_dict[step].append(test) | |
| 184 else: | |
| 185 shrinked_dict[step].extend(tests) | |
| 186 return shrinked_dict | |
| 187 | |
| 188 | |
| 189 def RunSteps(api, target_mastername, target_testername, good_revision, | |
| 190 bad_revision, tests, use_analyze, suspected_revisions): | |
| 169 assert tests, 'No failed tests were specified.' | 191 assert tests, 'No failed tests were specified.' |
| 170 | 192 |
| 171 # Figure out which builder configuration we should match for compile config. | 193 # Figure out which builder configuration we should match for compile config. |
| 172 # Sometimes, the builder itself runs the tests and there is no tester. In | 194 # Sometimes, the builder itself runs the tests and there is no tester. In |
| 173 # such cases, just treat the builder as a "tester". Thus, we default to | 195 # such cases, just treat the builder as a "tester". Thus, we default to |
| 174 # the target tester. | 196 # the target tester. |
| 175 tester_config = api.chromium_tests.builders.get( | 197 tester_config = api.chromium_tests.builders.get( |
| 176 target_mastername).get('builders', {}).get(target_testername) | 198 target_mastername).get('builders', {}).get(target_testername) |
| 177 target_buildername = (tester_config.get('parent_buildername') or | 199 target_buildername = (tester_config.get('parent_buildername') or |
| 178 target_testername) | 200 target_testername) |
| (...skipping 11 matching lines...) Expand all Loading... | |
| 190 api.swarming.set_default_dimension(key, value) | 212 api.swarming.set_default_dimension(key, value) |
| 191 # TODO(stgao): Fix the issue that precommit=False adds the tag 'purpose:CI'. | 213 # TODO(stgao): Fix the issue that precommit=False adds the tag 'purpose:CI'. |
| 192 api.chromium_tests.configure_swarming('chromium', precommit=False) | 214 api.chromium_tests.configure_swarming('chromium', precommit=False) |
| 193 | 215 |
| 194 # Sync to bad revision, and retrieve revisions in the regression range. | 216 # Sync to bad revision, and retrieve revisions in the regression range. |
| 195 api.chromium_tests.prepare_checkout( | 217 api.chromium_tests.prepare_checkout( |
| 196 bot_config, | 218 bot_config, |
| 197 root_solution_revision=bad_revision) | 219 root_solution_revision=bad_revision) |
| 198 revisions_to_check = api.findit.revisions_between(good_revision, bad_revision) | 220 revisions_to_check = api.findit.revisions_between(good_revision, bad_revision) |
| 199 | 221 |
| 222 suspected_revision_index = [ | |
| 223 revisions_to_check.index(r) | |
| 224 for r in set(suspected_revisions) if r in revisions_to_check] | |
| 225 | |
| 226 # Segments revisions_to_check by suspected_revisions. | |
| 227 # Each sub_range will contain following elements: | |
| 228 # 1. Revision before a suspected_revision or None as a placeholder | |
| 229 # when no such revision | |
| 230 # 2. Suspected_revision | |
| 231 # 3. Revisions between a suspected_revision and the revision before next | |
| 232 # suspected_revision, or remaining revisions before all suspect_revisions. | |
| 233 # For example, if revisions_to_check are [r0, r1, ..., r6] and | |
| 234 # suspected_revisions are [r2, r5], sub_ranges will be: | |
| 235 # [[None, r0], [r1, r2, r3], [r4, r5, r6]] | |
| 236 if suspected_revision_index: | |
| 237 sub_ranges = [] | |
| 238 remaining_revisions = revisions_to_check[:] | |
| 239 for index in sorted(suspected_revision_index, reverse=True): | |
| 240 if index > 0: | |
| 241 if index < len(remaining_revisions): | |
| 242 sub_ranges.append(remaining_revisions[index - 1:]) | |
| 243 else: # Consecutive revisions are suspected, merges them in one range. | |
| 244 sub_ranges[-1].insert(0, remaining_revisions[index - 1]) | |
| 245 remaining_revisions = remaining_revisions[:index - 1] | |
| 246 # None is a placeholder for the last known good revision. | |
| 247 sub_ranges.append([None] + remaining_revisions) | |
| 248 else: | |
| 249 # Treats the entire regression range as a single sub-range. | |
| 250 sub_ranges = [[None] + revisions_to_check] | |
| 251 | |
| 200 test_results = {} | 252 test_results = {} |
| 201 try_job_metadata = { | 253 try_job_metadata = { |
| 202 'regression_range_size': len(revisions_to_check) | 254 'regression_range_size': len(revisions_to_check) |
| 203 } | 255 } |
| 204 report = { | 256 report = { |
| 205 'result': test_results, | 257 'result': test_results, |
| 206 'metadata': try_job_metadata | 258 'metadata': try_job_metadata |
| 207 } | 259 } |
| 208 | 260 |
| 209 try: | 261 try: |
| 210 # We compile & run tests from the first revision to the last revision in the | 262 # Tests that haven't found culprits in tested revision(s). |
| 211 # regression range serially instead of a typical bisecting, because jumping | 263 no_culprit_tests = tests |
| 212 # between new and old revisions might affect Goma capacity and build cycle | 264 # Iterates through sub_ranges and find culprits for each failed test. |
| 213 # times. Thus we plan to go with this simple serial approach first so that | 265 for sub_range in sub_ranges: |
| 214 # compile would be fast due to incremental compile. | 266 if not no_culprit_tests: # All tests have found culprits |
|
lijeffrey
2016/05/03 23:25:44
nit: comment should end with a .
chanli
2016/05/04 17:14:40
Done.
| |
| 215 # If this won't work out, we will figure out a better solution for speed of | 267 break |
| 216 # both compile and test. | 268 |
| 217 for current_revision in revisions_to_check: | 269 potential_green_rev = sub_range[0] |
|
lijeffrey
2016/05/03 23:25:44
nit: Add a comment that potential_green_rev is the
chanli
2016/05/04 17:14:40
Done.
| |
| 218 test_results[current_revision] = _compile_and_test_at_revision( | 270 following_revisions = sub_range[1:] |
| 219 api, target_mastername, target_buildername, target_testername, | 271 if potential_green_rev: |
| 220 current_revision, tests, use_analyze) | 272 test_results[potential_green_rev], tests_failed_in_potential_green = ( |
| 221 # TODO(http://crbug.com/566975): check whether culprits for all failed | 273 _compile_and_test_at_revision( |
| 222 # tests are found and stop running tests at later revisions if so. | 274 api, target_mastername, target_buildername, target_testername, |
| 275 potential_green_rev, no_culprit_tests, use_analyze)) | |
| 276 else: | |
| 277 tests_failed_in_potential_green = {} | |
| 278 | |
| 279 tests_passed_in_potential_green = _get_shrinked_test_dict( | |
| 280 no_culprit_tests, tests_failed_in_potential_green) | |
| 281 | |
| 282 # Culprits for tests that failed in potential green should be earlier. | |
|
lijeffrey
2016/05/03 23:25:44
nit: failed in the revision before suspected revis
chanli
2016/05/04 17:14:40
Modified the whole sentence.
| |
| 283 # Thus no need to run passed tests in following revisions, | |
| 284 # only runs the tests that failed in following revisions. | |
|
lijeffrey
2016/05/03 23:25:44
nit: Culprits for tests that failed in potential g
chanli
2016/05/04 17:14:40
Done.
| |
| 285 if tests_passed_in_potential_green: | |
| 286 tests_to_run = tests_passed_in_potential_green | |
| 287 for revision in following_revisions: | |
| 288 test_results[revision], tests_failed_in_revision = ( | |
| 289 _compile_and_test_at_revision( | |
| 290 api, target_mastername, target_buildername, target_testername, | |
| 291 revision, tests_to_run, use_analyze)) | |
| 292 | |
| 293 # Takes out tests that passed in potential green and failed in | |
| 294 # following revisions: culprits have been found for them. | |
| 295 no_culprit_tests = _get_shrinked_test_dict( | |
| 296 no_culprit_tests, tests_failed_in_revision) | |
| 297 | |
| 298 # Only runs tests that have not found culprits in later revisions. | |
| 299 tests_to_run = _get_shrinked_test_dict( | |
| 300 tests_to_run, tests_failed_in_revision) | |
| 301 | |
| 302 if not tests_to_run: | |
| 303 break | |
| 304 | |
| 223 finally: | 305 finally: |
| 224 # Give the full report including test results and metadata. | 306 # Give the full report including test results and metadata. |
| 225 step_result = api.python.succeeding_step( | 307 step_result = api.python.succeeding_step( |
| 226 'report', [json.dumps(report, indent=2)], as_log='report') | 308 'report', [json.dumps(report, indent=2)], as_log='report') |
| 227 | 309 |
| 228 # Set the report as a build property too, so that it will be reported back | 310 # Set the report as a build property too, so that it will be reported back |
| 229 # to Buildbucket and Findit will pull from there instead of buildbot master. | 311 # to Buildbucket and Findit will pull from there instead of buildbot master. |
| 230 step_result.presentation.properties['report'] = report | 312 step_result.presentation.properties['report'] = report |
| 231 | 313 |
| 232 return report | 314 return report |
| 233 | 315 |
| 234 | 316 |
| 235 def GenTests(api): | 317 def GenTests(api): |
| 236 def props(tests, platform_name, tester_name, use_analyze=False): | 318 def props( |
| 319 tests, platform_name, tester_name, use_analyze=False, good_revision=None, | |
| 320 bad_revision=None, suspected_revisions=None): | |
| 237 properties = { | 321 properties = { |
| 238 'mastername': 'tryserver.chromium.%s' % platform_name, | 322 'mastername': 'tryserver.chromium.%s' % platform_name, |
| 239 'buildername': '%s_chromium_variable' % platform_name, | 323 'buildername': '%s_chromium_variable' % platform_name, |
| 240 'slavename': 'build1-a1', | 324 'slavename': 'build1-a1', |
| 241 'buildnumber': 1, | 325 'buildnumber': 1, |
| 242 'target_mastername': 'chromium.%s' % platform_name, | 326 'target_mastername': 'chromium.%s' % platform_name, |
| 243 'target_testername': tester_name, | 327 'target_testername': tester_name, |
| 244 'good_revision': 'r0', | 328 'good_revision': good_revision or 'r0', |
| 245 'bad_revision': 'r1', | 329 'bad_revision': bad_revision or 'r1', |
| 246 'tests': tests, | 330 'tests': tests, |
| 247 'use_analyze': use_analyze, | 331 'use_analyze': use_analyze, |
| 248 } | 332 } |
| 333 if suspected_revisions: | |
| 334 properties['suspected_revisions'] = suspected_revisions | |
| 249 return api.properties(**properties) + api.platform.name(platform_name) | 335 return api.properties(**properties) + api.platform.name(platform_name) |
| 250 | 336 |
| 251 def simulated_gtest_output(failed_test_names=(), passed_test_names=()): | 337 def simulated_gtest_output(failed_test_names=(), passed_test_names=()): |
| 252 cur_iteration_data = {} | 338 cur_iteration_data = {} |
| 253 for test_name in failed_test_names: | 339 for test_name in failed_test_names: |
| 254 cur_iteration_data[test_name] = [{ | 340 cur_iteration_data[test_name] = [{ |
| 255 'elapsed_time_ms': 0, | 341 'elapsed_time_ms': 0, |
| 256 'output_snippet': '', | 342 'output_snippet': '', |
| 257 'status': 'FAILURE', | 343 'status': 'FAILURE', |
| 258 }] | 344 }] |
| (...skipping 201 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... | |
| 460 'swarming': {'can_use_on_swarming_builders': True}, | 546 'swarming': {'can_use_on_swarming_builders': True}, |
| 461 }, | 547 }, |
| 462 ], | 548 ], |
| 463 }, | 549 }, |
| 464 })) + | 550 })) + |
| 465 api.override_step_data( | 551 api.override_step_data( |
| 466 'test r1.gl_tests (r1) on Mac-10.9', | 552 'test r1.gl_tests (r1) on Mac-10.9', |
| 467 simulated_gtest_output(passed_test_names=['Test.One']) | 553 simulated_gtest_output(passed_test_names=['Test.One']) |
| 468 ) | 554 ) |
| 469 ) | 555 ) |
| 556 | |
| 557 yield ( | |
| 558 api.test('findit_culprit_in_last_sub_range') + | |
| 559 props( | |
| 560 {'gl_tests': ['Test.One']}, 'mac', 'Mac10.9 Tests', use_analyze=False, | |
| 561 good_revision='r0', bad_revision='r6', suspected_revisions=['r3']) + | |
| 562 api.override_step_data('test r2.read test spec', api.json.output({ | |
| 563 'Mac10.9 Tests': { | |
| 564 'gtest_tests': [ | |
| 565 { | |
| 566 'test': 'gl_tests', | |
| 567 'swarming': {'can_use_on_swarming_builders': True}, | |
| 568 }, | |
| 569 ], | |
| 570 }, | |
| 571 })) + | |
| 572 api.override_step_data('test r3.read test spec', api.json.output({ | |
| 573 'Mac10.9 Tests': { | |
| 574 'gtest_tests': [ | |
| 575 { | |
| 576 'test': 'gl_tests', | |
| 577 'swarming': {'can_use_on_swarming_builders': True}, | |
| 578 }, | |
| 579 ], | |
| 580 }, | |
| 581 })) + | |
| 582 api.override_step_data( | |
| 583 'git commits in range', | |
| 584 api.raw_io.stream_output( | |
| 585 '\n'.join('r%d' % i for i in reversed(range(1, 7))))) + | |
| 586 api.override_step_data( | |
| 587 'test r2.gl_tests (r2) on Mac-10.9', | |
| 588 simulated_gtest_output(passed_test_names=['Test.One'])) + | |
| 589 api.override_step_data( | |
| 590 'test r3.gl_tests (r3) on Mac-10.9', | |
| 591 simulated_gtest_output(failed_test_names=['Test.One'])) | |
| 592 ) | |
| 593 | |
| 594 yield ( | |
| 595 api.test('findit_culprit_in_middle_sub_range') + | |
| 596 props( | |
| 597 {'gl_tests': ['Test.One']}, 'mac', 'Mac10.9 Tests', use_analyze=False, | |
| 598 good_revision='r0', bad_revision='r6', | |
| 599 suspected_revisions=['r3', 'r6']) + | |
| 600 api.override_step_data('test r2.read test spec', api.json.output({ | |
| 601 'Mac10.9 Tests': { | |
| 602 'gtest_tests': [ | |
| 603 { | |
| 604 'test': 'gl_tests', | |
| 605 'swarming': {'can_use_on_swarming_builders': True}, | |
| 606 }, | |
| 607 ], | |
| 608 }, | |
| 609 })) + | |
| 610 api.override_step_data('test r3.read test spec', api.json.output({ | |
| 611 'Mac10.9 Tests': { | |
| 612 'gtest_tests': [ | |
| 613 { | |
| 614 'test': 'gl_tests', | |
| 615 'swarming': {'can_use_on_swarming_builders': True}, | |
| 616 }, | |
| 617 ], | |
| 618 }, | |
| 619 })) + | |
| 620 api.override_step_data('test r5.read test spec', api.json.output({ | |
| 621 'Mac10.9 Tests': { | |
| 622 'gtest_tests': [ | |
| 623 { | |
| 624 'test': 'gl_tests', | |
| 625 'swarming': {'can_use_on_swarming_builders': True}, | |
| 626 }, | |
| 627 ], | |
| 628 }, | |
| 629 })) + | |
| 630 api.override_step_data('test r6.read test spec', api.json.output({ | |
| 631 'Mac10.9 Tests': { | |
| 632 'gtest_tests': [ | |
| 633 { | |
| 634 'test': 'gl_tests', | |
| 635 'swarming': {'can_use_on_swarming_builders': True}, | |
| 636 }, | |
| 637 ], | |
| 638 }, | |
| 639 })) + | |
| 640 api.override_step_data( | |
| 641 'git commits in range', | |
| 642 api.raw_io.stream_output( | |
| 643 '\n'.join('r%d' % i for i in reversed(range(1, 7))))) + | |
| 644 api.override_step_data( | |
| 645 'test r2.gl_tests (r2) on Mac-10.9', | |
| 646 simulated_gtest_output(passed_test_names=['Test.One'])) + | |
| 647 api.override_step_data( | |
| 648 'test r3.gl_tests (r3) on Mac-10.9', | |
| 649 simulated_gtest_output(failed_test_names=['Test.One'])) + | |
| 650 api.override_step_data( | |
| 651 'test r5.gl_tests (r5) on Mac-10.9', | |
| 652 simulated_gtest_output(passed_test_names=['Test.One'])) + | |
| 653 api.override_step_data( | |
| 654 'test r6.gl_tests (r6) on Mac-10.9', | |
| 655 simulated_gtest_output(passed_test_names=['Test.One'])) | |
| 656 ) | |
| 657 | |
| 658 yield ( | |
| 659 api.test('findit_culprit_in_first_sub_range') + | |
| 660 props( | |
| 661 {'gl_tests': ['Test.One']}, 'mac', 'Mac10.9 Tests', use_analyze=False, | |
| 662 good_revision='r0', bad_revision='r6', | |
| 663 suspected_revisions=['r6']) + | |
| 664 api.override_step_data('test r1.read test spec', api.json.output({ | |
| 665 'Mac10.9 Tests': { | |
| 666 'gtest_tests': [ | |
| 667 { | |
| 668 'test': 'gl_tests', | |
| 669 'swarming': {'can_use_on_swarming_builders': True}, | |
| 670 }, | |
| 671 ], | |
| 672 }, | |
| 673 })) + | |
| 674 api.override_step_data('test r5.read test spec', api.json.output({ | |
| 675 'Mac10.9 Tests': { | |
| 676 'gtest_tests': [ | |
| 677 { | |
| 678 'test': 'gl_tests', | |
| 679 'swarming': {'can_use_on_swarming_builders': True}, | |
| 680 }, | |
| 681 ], | |
| 682 }, | |
| 683 })) + | |
| 684 api.override_step_data('test r6.read test spec', api.json.output({ | |
| 685 'Mac10.9 Tests': { | |
| 686 'gtest_tests': [ | |
| 687 { | |
| 688 'test': 'gl_tests', | |
| 689 'swarming': {'can_use_on_swarming_builders': True}, | |
| 690 }, | |
| 691 ], | |
| 692 }, | |
| 693 })) + | |
| 694 api.override_step_data( | |
| 695 'git commits in range', | |
| 696 api.raw_io.stream_output( | |
| 697 '\n'.join('r%d' % i for i in reversed(range(1, 7))))) + | |
| 698 api.override_step_data( | |
| 699 'test r1.gl_tests (r1) on Mac-10.9', | |
| 700 simulated_gtest_output(failed_test_names=['Test.One'])) + | |
| 701 api.override_step_data( | |
| 702 'test r5.gl_tests (r5) on Mac-10.9', | |
| 703 simulated_gtest_output(passed_test_names=['Test.One'])) + | |
| 704 api.override_step_data( | |
| 705 'test r6.gl_tests (r6) on Mac-10.9', | |
| 706 simulated_gtest_output(passed_test_names=['Test.One'])) | |
| 707 ) | |
| 708 | |
| 709 yield ( | |
| 710 api.test('findit_steps_multiple_culprits') + | |
| 711 props( | |
| 712 {'gl_tests': ['Test.gl_One'], 'browser_tests': ['Test.browser_One']}, | |
| 713 'mac', 'Mac10.9 Tests', use_analyze=False, | |
| 714 good_revision='r0', bad_revision='r6', | |
| 715 suspected_revisions=['r3','r6']) + | |
| 716 api.override_step_data('test r2.read test spec', api.json.output({ | |
| 717 'Mac10.9 Tests': { | |
| 718 'gtest_tests': [ | |
| 719 { | |
| 720 'test': 'gl_tests', | |
| 721 'swarming': {'can_use_on_swarming_builders': True}, | |
| 722 }, | |
| 723 { | |
| 724 'test': 'browser_tests', | |
| 725 'swarming': {'can_use_on_swarming_builders': True}, | |
| 726 }, | |
| 727 ], | |
| 728 }, | |
| 729 })) + | |
| 730 api.override_step_data('test r3.read test spec', api.json.output({ | |
| 731 'Mac10.9 Tests': { | |
| 732 'gtest_tests': [ | |
| 733 { | |
| 734 'test': 'gl_tests', | |
| 735 'swarming': {'can_use_on_swarming_builders': True}, | |
| 736 }, | |
| 737 { | |
| 738 'test': 'browser_tests', | |
| 739 'swarming': {'can_use_on_swarming_builders': True}, | |
| 740 }, | |
| 741 ], | |
| 742 }, | |
| 743 })) + | |
| 744 api.override_step_data('test r5.read test spec', api.json.output({ | |
| 745 'Mac10.9 Tests': { | |
| 746 'gtest_tests': [ | |
| 747 { | |
| 748 'test': 'gl_tests', | |
| 749 'swarming': {'can_use_on_swarming_builders': True}, | |
| 750 }, | |
| 751 { | |
| 752 'test': 'browser_tests', | |
| 753 'swarming': {'can_use_on_swarming_builders': True}, | |
| 754 }, | |
| 755 ], | |
| 756 }, | |
| 757 })) + | |
| 758 api.override_step_data('test r6.read test spec', api.json.output({ | |
| 759 'Mac10.9 Tests': { | |
| 760 'gtest_tests': [ | |
| 761 { | |
| 762 'test': 'gl_tests', | |
| 763 'swarming': {'can_use_on_swarming_builders': True}, | |
| 764 }, | |
| 765 { | |
| 766 'test': 'browser_tests', | |
| 767 'swarming': {'can_use_on_swarming_builders': True}, | |
| 768 }, | |
| 769 ], | |
| 770 }, | |
| 771 })) + | |
| 772 api.override_step_data( | |
| 773 'git commits in range', | |
| 774 api.raw_io.stream_output( | |
| 775 '\n'.join('r%d' % i for i in reversed(range(1, 7))))) + | |
| 776 api.override_step_data( | |
| 777 'test r5.gl_tests (r5) on Mac-10.9', | |
| 778 simulated_gtest_output(failed_test_names=['Test.gl_One'])) + | |
| 779 api.override_step_data( | |
| 780 'test r5.browser_tests (r5) on Mac-10.9', | |
| 781 simulated_gtest_output(passed_test_names=['Test.browser_One'])) + | |
| 782 api.override_step_data( | |
| 783 'test r6.browser_tests (r6) on Mac-10.9', | |
| 784 simulated_gtest_output(failed_test_names=['Test.browser_One']))+ | |
| 785 api.override_step_data( | |
| 786 'test r2.gl_tests (r2) on Mac-10.9', | |
| 787 simulated_gtest_output(passed_test_names=['Test.gl_One'])) + | |
| 788 api.override_step_data( | |
| 789 'test r3.gl_tests (r3) on Mac-10.9', | |
| 790 simulated_gtest_output(failed_test_names=['Test.gl_One'])) | |
| 791 ) | |
| 792 | |
| 793 yield ( | |
| 794 api.test('findit_tests_multiple_culprits') + | |
| 795 props( | |
| 796 {'gl_tests': ['Test.One', 'Test.Two', 'Test.Three']}, | |
| 797 'mac', 'Mac10.9 Tests', use_analyze=False, | |
| 798 good_revision='r0', bad_revision='r6', | |
| 799 suspected_revisions=['r3', 'r5']) + | |
| 800 api.override_step_data('test r2.read test spec', api.json.output({ | |
| 801 'Mac10.9 Tests': { | |
| 802 'gtest_tests': [ | |
| 803 { | |
| 804 'test': 'gl_tests', | |
| 805 'swarming': {'can_use_on_swarming_builders': True}, | |
| 806 }, | |
| 807 ], | |
| 808 }, | |
| 809 })) + | |
| 810 api.override_step_data('test r3.read test spec', api.json.output({ | |
| 811 'Mac10.9 Tests': { | |
| 812 'gtest_tests': [ | |
| 813 { | |
| 814 'test': 'gl_tests', | |
| 815 'swarming': {'can_use_on_swarming_builders': True}, | |
| 816 }, | |
| 817 ], | |
| 818 }, | |
| 819 })) + | |
| 820 api.override_step_data('test r4.read test spec', api.json.output({ | |
| 821 'Mac10.9 Tests': { | |
| 822 'gtest_tests': [ | |
| 823 { | |
| 824 'test': 'gl_tests', | |
| 825 'swarming': {'can_use_on_swarming_builders': True}, | |
| 826 }, | |
| 827 ], | |
| 828 }, | |
| 829 })) + | |
| 830 api.override_step_data('test r5.read test spec', api.json.output({ | |
| 831 'Mac10.9 Tests': { | |
| 832 'gtest_tests': [ | |
| 833 { | |
| 834 'test': 'gl_tests', | |
| 835 'swarming': {'can_use_on_swarming_builders': True}, | |
| 836 }, | |
| 837 ], | |
| 838 }, | |
| 839 })) + | |
| 840 api.override_step_data('test r6.read test spec', api.json.output({ | |
| 841 'Mac10.9 Tests': { | |
| 842 'gtest_tests': [ | |
| 843 { | |
| 844 'test': 'gl_tests', | |
| 845 'swarming': {'can_use_on_swarming_builders': True}, | |
| 846 }, | |
| 847 ], | |
| 848 }, | |
| 849 })) + | |
| 850 api.override_step_data( | |
| 851 'git commits in range', | |
| 852 api.raw_io.stream_output( | |
| 853 '\n'.join('r%d' % i for i in reversed(range(1, 7))))) + | |
| 854 api.override_step_data( | |
| 855 'test r4.gl_tests (r4) on Mac-10.9', | |
| 856 simulated_gtest_output(passed_test_names=['Test.One', 'Test.Three'], | |
| 857 failed_test_names=['Test.Two'])) + | |
| 858 api.override_step_data( | |
| 859 'test r5.gl_tests (r5) on Mac-10.9', | |
| 860 simulated_gtest_output(passed_test_names=['Test.One'], | |
| 861 failed_test_names=['Test.Three'])) + | |
| 862 api.override_step_data( | |
| 863 'test r6.gl_tests (r6) on Mac-10.9', | |
| 864 simulated_gtest_output(failed_test_names=['Test.One']))+ | |
| 865 api.override_step_data( | |
| 866 'test r2.gl_tests (r2) on Mac-10.9', | |
| 867 simulated_gtest_output(passed_test_names=['Test.Two'])) + | |
| 868 api.override_step_data( | |
| 869 'test r3.gl_tests (r3) on Mac-10.9', | |
| 870 simulated_gtest_output(failed_test_names=['Test.Two'])) | |
| 871 ) | |
| OLD | NEW |