| 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 import json | 5 import json |
| 6 | 6 |
| 7 DEPS = [ | 7 DEPS = [ |
| 8 'auto_bisect', | 8 'auto_bisect', |
| 9 'chromium_tests', | 9 'chromium_tests', |
| 10 'depot_tools/gclient', |
| 10 'recipe_engine/json', | 11 'recipe_engine/json', |
| 11 'recipe_engine/path', | 12 'recipe_engine/path', |
| 12 'recipe_engine/properties', | 13 'recipe_engine/properties', |
| 13 'recipe_engine/raw_io', | 14 'recipe_engine/raw_io', |
| 14 'recipe_engine/step', | 15 'recipe_engine/step', |
| 15 ] | 16 ] |
| 16 | 17 |
| 17 """This file is a recipe demonstrating the auto_bisect recipe module. | 18 """This file is a recipe demonstrating the auto_bisect recipe module. |
| 18 | 19 |
| 19 For more information about recipes, see: https://goo.gl/xKnjz6 | 20 For more information about recipes, see: https://goo.gl/xKnjz6 |
| 20 """ | 21 """ |
| 21 | 22 |
| 22 | 23 |
| 23 def RunSteps(api): | 24 def RunSteps(api): |
| 25 mastername = api.properties.get('mastername') |
| 26 buildername = api.properties.get('buildername') |
| 27 bot_config = api.chromium_tests.create_bot_config_object(mastername, |
| 28 buildername) |
| 29 api.chromium_tests.configure_build(bot_config) |
| 30 api.gclient.apply_config('perf') |
| 31 update_step, bot_db = api.chromium_tests.prepare_checkout(bot_config) |
| 32 |
| 33 api.auto_bisect.bot_db = bot_db |
| 34 |
| 24 fake_checkout_path = api.path.mkdtemp('fake_checkout') | 35 fake_checkout_path = api.path.mkdtemp('fake_checkout') |
| 25 api.path['checkout'] = fake_checkout_path | 36 api.path['checkout'] = fake_checkout_path |
| 37 api.path.c.dynamic_paths['catapult'] = api.path['slave_build'].join( |
| 38 'catapult') |
| 26 bisector = api.auto_bisect.create_bisector(api.properties['bisect_config'], | 39 bisector = api.auto_bisect.create_bisector(api.properties['bisect_config'], |
| 27 do_not_nest_wait_for_revision=True) | 40 do_not_nest_wait_for_revision=True) |
| 28 | 41 |
| 29 # Request builds and tests for initial range and wait. | |
| 30 bisector.good_rev.start_job() | 42 bisector.good_rev.start_job() |
| 43 if bisector.good_rev.failed: |
| 44 return |
| 45 |
| 31 bisector.bad_rev.start_job() | 46 bisector.bad_rev.start_job() |
| 32 bisector.wait_for_all([bisector.good_rev, bisector.bad_rev]) | 47 if bisector.bad_rev.failed: |
| 33 | |
| 34 if bisector.good_rev.failed or bisector.bad_rev.failed: | |
| 35 return | 48 return |
| 36 | 49 |
| 37 assert bisector.check_improvement_direction() | 50 assert bisector.check_improvement_direction() |
| 38 assert bisector.check_initial_confidence() | 51 assert bisector.check_initial_confidence() |
| 39 revision_to_check = bisector.get_revision_to_eval() | 52 revision_to_check = bisector.get_revision_to_eval() |
| 40 revision_to_check.start_job() | 53 revision_to_check.start_job() |
| 41 bisector.wait_for(revision_to_check) | |
| 42 bisector.check_bisect_finished(revision_to_check) | 54 bisector.check_bisect_finished(revision_to_check) |
| 43 | 55 |
| 44 # Evaluate inserted DEPS-modified revisions. | 56 # Evaluate inserted DEPS-modified revisions. |
| 45 revision_to_check = bisector.get_revision_to_eval() | 57 revision_to_check = bisector.get_revision_to_eval() |
| 46 if revision_to_check: | 58 if revision_to_check: |
| 47 revision_to_check.start_job() | 59 revision_to_check.start_job() |
| 48 # Only added for coverage. | 60 # Only added for coverage. |
| 49 revision_to_check.read_deps(bisector.get_perf_tester_name()) | 61 revision_to_check.read_deps(bisector.get_perf_tester_name()) |
| 50 api.auto_bisect.query_revision_info(revision_to_check) | 62 api.auto_bisect.query_revision_info(revision_to_check) |
| 51 else: | 63 else: |
| 52 raise api.step.StepFailure('Expected revision to check.') | 64 raise api.step.StepFailure('Expected revision to check.') |
| 53 # TODO(robertocn): Add examples for the following operations: | 65 # TODO(robertocn): Add examples for the following operations: |
| 54 # Abort unnecessary jobs | 66 # Abort unnecessary jobs |
| 55 # Print results (may be done in a unit test) | 67 # Print results (may be done in a unit test) |
| 56 | 68 |
| 57 # Test runner for classic bisect script; calls bisect script in recipe | 69 # Test runner for classic bisect script; calls bisect script in recipe |
| 58 # wrapper with extra_src and path_to_config to override default behavior for | 70 # wrapper with extra_src and path_to_config to override default behavior for |
| 59 # android-chrome bisect jobs. | 71 # android-chrome bisect jobs. |
| 60 if api.properties.get('mastername'): | 72 if api.properties.get('mastername'): |
| 61 # TODO(akuegel): Load the config explicitly instead of relying on the | 73 # TODO(akuegel): Load the config explicitly instead of relying on the |
| 62 # builders.py entries in chromium_tests. | 74 # builders.py entries in chromium_tests. |
| 63 mastername = api.properties.get('mastername') | 75 mastername = api.properties.get('mastername') |
| 64 buildername = api.properties.get('buildername') | 76 buildername = api.properties.get('buildername') |
| 65 bot_config = api.chromium_tests.create_bot_config_object( | 77 bot_config = api.chromium_tests.create_bot_config_object( |
| 66 mastername, buildername) | 78 mastername, buildername) |
| 67 api.chromium_tests.configure_build(bot_config) | 79 api.chromium_tests.configure_build(bot_config) |
| 80 api.gclient.c.got_revision_mapping.pop('catapult', None) |
| 68 api.chromium_tests.prepare_checkout(bot_config) | 81 api.chromium_tests.prepare_checkout(bot_config) |
| 69 kwargs = { | 82 kwargs = { |
| 70 'extra_src': 'dummy_extra_src', | 83 'extra_src': 'dummy_extra_src', |
| 71 'path_to_config': '/dummy/path/', | 84 'path_to_config': '/dummy/path/', |
| 72 } | 85 } |
| 73 api.auto_bisect.run_bisect_script(**kwargs) | 86 api.auto_bisect.run_bisect_script(**kwargs) |
| 74 | 87 |
| 75 | 88 |
| 76 def GenTests(api): | 89 def GenTests(api): |
| 77 dummy_gs_location = ('gs://chrome-perf/bisect-results/' | 90 dummy_gs_location = ('gs://chrome-perf/bisect-results/' |
| 78 'a6298e4afedbf2cd461755ea6f45b0ad64222222-test.results') | 91 'a6298e4afedbf2cd461755ea6f45b0ad64222222-test.results') |
| 92 bisect_script_test = _make_test( |
| 93 api, _get_basic_test_data(), 'basic_bisect_script') |
| 94 |
| 95 bisect_script_test += api.properties(mastername='tryserver.chromium.perf', |
| 96 buildername='linux_perf_bisect', |
| 97 slavename='dummyslave') |
| 98 yield bisect_script_test |
| 99 |
| 79 basic_test = _make_test(api, _get_basic_test_data(), 'basic') | 100 basic_test = _make_test(api, _get_basic_test_data(), 'basic') |
| 80 yield basic_test | 101 yield basic_test |
| 81 | 102 |
| 103 yield _make_test(api, _get_reversed_basic_test_data(), 'reversed_basic') |
| 104 |
| 82 invalid_config_test = api.test('invalid_config') | 105 invalid_config_test = api.test('invalid_config') |
| 83 invalid_config_test += api.properties( | 106 invalid_config_test += api.properties( |
| 84 bisect_config=_get_config({'good_revision': 'not a valid revision'})) | 107 bisect_config=_get_config({'good_revision': 'not a valid revision'})) |
| 85 yield invalid_config_test | 108 yield invalid_config_test |
| 86 | 109 |
| 110 missing_metric_test = _make_test( |
| 111 api, _get_ref_range_only_missing_metric_test_data(), |
| 112 'missing_metric_test') |
| 113 yield missing_metric_test |
| 114 |
| 115 windows_test = _make_test( |
| 116 api, _get_basic_test_data(), 'windows_bisector', platform='windows') |
| 117 yield windows_test |
| 118 |
| 119 winx64_test = _make_test( |
| 120 api, _get_basic_test_data(), 'windows_x64_bisector', platform='win_x64') |
| 121 yield winx64_test |
| 122 |
| 123 mac_test = _make_test( |
| 124 api, _get_basic_test_data(), 'mac_bisector', platform='mac') |
| 125 yield mac_test |
| 126 |
| 127 android_test = _make_test( |
| 128 api, _get_basic_test_data(), 'android_bisector', platform='android') |
| 129 yield android_test |
| 130 |
| 131 android_arm64_test = _make_test( |
| 132 api, _get_basic_test_data(), 'android_arm64_bisector', |
| 133 platform='android_arm64') |
| 134 yield android_arm64_test |
| 135 |
| 136 failed_data = _get_basic_test_data() |
| 137 failed_data[0].pop('DEPS') |
| 138 failed_data[1]['test_results']['results']['errors'] = ['Dummy error.'] |
| 139 failed_data[1].pop('DEPS_change') |
| 140 failed_data[1].pop('DEPS') |
| 141 failed_data[1].pop('DEPS_interval') |
| 142 failed_data[0].pop('git_diff') |
| 143 failed_data[0].pop('cl_info') |
| 144 yield _make_test(api, failed_data, 'failed_test') |
| 145 |
| 87 failed_build_test = _make_test( | 146 failed_build_test = _make_test( |
| 88 api, _get_ref_range_only_test_data(), 'failed_build_test', | 147 api, _get_ref_range_only_test_data(), 'failed_build_test', |
| 89 extra_config={'dummy_builds': None}) | 148 extra_config={'dummy_builds': None}) |
| 90 failed_build_test += api.step_data('gsutil ls', retcode=1) | 149 failed_build_test += api.step_data('gsutil ls', retcode=1) |
| 91 failed_build_test += api.step_data('gsutil ls (2)' , retcode=1) | 150 failed_build_test += api.step_data('gsutil ls (2)' , retcode=1) |
| 92 failed_build_test += api.step_data('gsutil ls (3)' , retcode=1) | 151 failed_build_test += api.step_data('gsutil ls (3)' , retcode=1) |
| 93 failed_build_test += api.step_data( | 152 failed_build_test += api.step_data( |
| 94 'fetch builder state', | 153 'fetch builder state', |
| 95 api.raw_io.output(json.dumps({'cachedBuilds': ['2106']}))) | 154 api.raw_io.output(json.dumps({'cachedBuilds': ['2106']}))) |
| 96 failed_build_test += api.step_data( | 155 failed_build_test += api.step_data( |
| 97 'fetch build details', | 156 'fetch build details', |
| 98 api.raw_io.output(json.dumps({ | 157 api.raw_io.output(json.dumps({ |
| 99 'results': 2, | 158 'results': 2, |
| 100 'properties': [('build_archive_url', | 159 'properties': [('build_archive_url', |
| 101 ('gs://chrome-perf/Linux Builder/full-build-linux_' | 160 ('gs://chrome-perf/Linux Builder/full-build-linux_' |
| 102 'a6298e4afedbf2cd461755ea6f45b0ad64222222.zip'))] | 161 'a6298e4afedbf2cd461755ea6f45b0ad64222222.zip'))] |
| 103 }))) | 162 }))) |
| 104 yield failed_build_test | 163 yield failed_build_test |
| 105 | 164 |
| 106 | |
| 107 delayed_build_test = _make_test( | 165 delayed_build_test = _make_test( |
| 108 api, _get_ref_range_only_test_data(), 'delayed_build_test', | 166 api, _get_ref_range_only_test_data(), 'delayed_build_test', |
| 109 extra_config={'dummy_builds': None}) | 167 extra_config={'dummy_builds': None}) |
| 110 delayed_build_test += api.step_data('gsutil ls', retcode=1) | 168 delayed_build_test += api.step_data('gsutil ls', retcode=1) |
| 111 delayed_build_test += api.step_data('gsutil ls (2)', retcode=1) | 169 delayed_build_test += api.step_data('gsutil ls (2)', retcode=1) |
| 112 delayed_build_test += api.step_data('gsutil ls (3)', retcode=1) | 170 delayed_build_test += api.step_data('gsutil ls (3)', retcode=1) |
| 113 delayed_build_test += api.step_data('gsutil ls (4)', retcode=1) | 171 delayed_build_test += api.step_data('gsutil ls (4)', retcode=1) |
| 114 delayed_build_test += api.step_data('gsutil ls (5)', retcode=1) | 172 delayed_build_test += api.step_data('gsutil ls (5)', retcode=1) |
| 115 delayed_build_test += api.step_data('gsutil ls (6)', retcode=1) | 173 delayed_build_test += api.step_data('gsutil ls (6)', retcode=1) |
| 116 delayed_build_test += api.step_data( | 174 delayed_build_test += api.step_data( |
| (...skipping 12 matching lines...) Expand all Loading... |
| 129 delayed_build_test += api.step_data( | 187 delayed_build_test += api.step_data( |
| 130 'fetch build details (2)', | 188 'fetch build details (2)', |
| 131 api.raw_io.output(json.dumps({ | 189 api.raw_io.output(json.dumps({ |
| 132 'results': 2, | 190 'results': 2, |
| 133 'properties': [('build_archive_url', | 191 'properties': [('build_archive_url', |
| 134 ('gs://chrome-perf/Linux Builder/full-build-linux_' | 192 ('gs://chrome-perf/Linux Builder/full-build-linux_' |
| 135 'a6298e4afedbf2cd461755ea6f45b0ad64222222.zip'))] | 193 'a6298e4afedbf2cd461755ea6f45b0ad64222222.zip'))] |
| 136 }))) | 194 }))) |
| 137 yield delayed_build_test | 195 yield delayed_build_test |
| 138 | 196 |
| 139 missing_metric_test = _make_test( | |
| 140 api, _get_ref_range_only_missing_metric_test_data(), | |
| 141 'missing_metric_test') | |
| 142 yield missing_metric_test | |
| 143 | |
| 144 windows_test = _make_test( | |
| 145 api, _get_basic_test_data(), 'windows_bisector', platform='windows') | |
| 146 yield windows_test | |
| 147 | |
| 148 winx64_test = _make_test( | |
| 149 api, _get_basic_test_data(), 'windows_x64_bisector', platform='win_x64') | |
| 150 yield winx64_test | |
| 151 | |
| 152 mac_test = _make_test( | |
| 153 api, _get_basic_test_data(), 'mac_bisector', platform='mac') | |
| 154 yield mac_test | |
| 155 | |
| 156 android_test = _make_test( | |
| 157 api, _get_basic_test_data(), 'android_bisector', platform='android') | |
| 158 yield android_test | |
| 159 | |
| 160 android_arm64_test = _make_test( | |
| 161 api, _get_basic_test_data(), 'android_arm64_bisector', | |
| 162 platform='android_arm64') | |
| 163 yield android_arm64_test | |
| 164 | |
| 165 failed_data = _get_basic_test_data() | |
| 166 failed_data[0].pop('DEPS') | |
| 167 failed_data[1]['test_results']['results']['errors'] = ['Dummy error.'] | |
| 168 failed_data[1].pop('DEPS_change') | |
| 169 failed_data[1].pop('DEPS') | |
| 170 failed_data[1].pop('DEPS_interval') | |
| 171 failed_data[0].pop('git_diff') | |
| 172 failed_data[0].pop('cl_info') | |
| 173 yield _make_test(api, failed_data, 'failed_test') | |
| 174 | |
| 175 yield _make_test(api, _get_reversed_basic_test_data(), 'reversed_basic') | |
| 176 | |
| 177 bad_git_hash_data = _get_basic_test_data() | |
| 178 bad_git_hash_data[1]['interned_hashes'] = {'003': '12345', '002': 'Bad Hash'} | |
| 179 | |
| 180 bisect_script_test = _make_test( | |
| 181 api, _get_basic_test_data(), 'basic_bisect_script') | |
| 182 | |
| 183 yield bisect_script_test | |
| 184 | |
| 185 | 197 |
| 186 def _get_ref_range_only_test_data(): | 198 def _get_ref_range_only_test_data(): |
| 187 return [ | 199 return [ |
| 188 { | 200 { |
| 189 'refrange': True, | 201 'refrange': True, |
| 190 'hash': 'a6298e4afedbf2cd461755ea6f45b0ad64222222', | 202 'hash': 'a6298e4afedbf2cd461755ea6f45b0ad64222222', |
| 191 'commit_pos': '314015', | 203 'commit_pos': '314015', |
| 192 'fail_to_build': True, | 204 'fail_to_build': True, |
| 193 }, | 205 }, |
| 194 { | 206 { |
| (...skipping 143 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
| 338 'DEPS_interval': {'v8': '002 003 004'.split()}, | 350 'DEPS_interval': {'v8': '002 003 004'.split()}, |
| 339 }, | 351 }, |
| 340 ] | 352 ] |
| 341 | 353 |
| 342 | 354 |
| 343 def _make_test(api, test_data, test_name, platform='linux', extra_config=None): | 355 def _make_test(api, test_data, test_name, platform='linux', extra_config=None): |
| 344 basic_test = api.test(test_name) | 356 basic_test = api.test(test_name) |
| 345 basic_test += api.properties(mastername='tryserver.chromium.perf', | 357 basic_test += api.properties(mastername='tryserver.chromium.perf', |
| 346 buildername='linux_perf_bisect', | 358 buildername='linux_perf_bisect', |
| 347 slavename='dummyslave') | 359 slavename='dummyslave') |
| 360 basic_test += api.auto_bisect() |
| 348 basic_test += _get_revision_range_step_data(api, test_data) | 361 basic_test += _get_revision_range_step_data(api, test_data) |
| 349 for revision_data in test_data: | 362 for revision_data in test_data: |
| 350 for step_data in _get_step_data_for_revision(api, revision_data): | 363 for step_data in _get_step_data_for_revision(api, revision_data): |
| 351 basic_test += step_data | 364 basic_test += step_data |
| 352 if 'win_x64' in platform: | 365 if 'win_x64' in platform: |
| 353 basic_test += api.properties(bisect_config=_get_config({ | 366 basic_test += api.properties(bisect_config=_get_config({ |
| 354 'command': ('src/tools/perf/run_benchmark -v --browser=release_x64' | 367 'command': ('src/tools/perf/run_benchmark -v --browser=release_x64' |
| 355 ' smoothness.tough_scrolling_cases'), | 368 ' smoothness.tough_scrolling_cases'), |
| 356 'recipe_tester_name': 'chromium_rel_win7_x64'})) | 369 'recipe_tester_name': 'chromium_rel_win7_x64'})) |
| 357 elif 'win' in platform: | 370 elif 'win' in platform: |
| (...skipping 79 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
| 437 if revision_data.get('DEPS', False): | 450 if revision_data.get('DEPS', False): |
| 438 step_name = 'fetch file %s:DEPS' % commit_hash | 451 step_name = 'fetch file %s:DEPS' % commit_hash |
| 439 yield api.step_data(step_name, stdout=api.raw_io.output( | 452 yield api.step_data(step_name, stdout=api.raw_io.output( |
| 440 revision_data['DEPS'])) | 453 revision_data['DEPS'])) |
| 441 | 454 |
| 442 if 'git_diff' in revision_data: | 455 if 'git_diff' in revision_data: |
| 443 for deps_rev, diff_file in revision_data['git_diff'].iteritems(): | 456 for deps_rev, diff_file in revision_data['git_diff'].iteritems(): |
| 444 step_name = 'Generating patch for %s:DEPS to %s' | 457 step_name = 'Generating patch for %s:DEPS to %s' |
| 445 step_name %= (commit_hash, deps_rev) | 458 step_name %= (commit_hash, deps_rev) |
| 446 yield api.step_data(step_name, stdout=api.raw_io.output(diff_file)) | 459 yield api.step_data(step_name, stdout=api.raw_io.output(diff_file)) |
| 460 if deps_rev == '003': |
| 461 step_name = ('gsutil Get test results for build %s') % deps_rev |
| 462 yield api.step_data(step_name, stdout=api.json.output(test_results)) |
| 447 | 463 |
| 448 if 'DEPS_change' in revision_data: | 464 if 'DEPS_change' in revision_data: |
| 449 step_name = 'Checking DEPS for ' + commit_hash | 465 step_name = 'Checking DEPS for ' + commit_hash |
| 450 yield api.step_data(step_name, stdout=api.raw_io.output('DEPS')) | 466 yield api.step_data(step_name, stdout=api.raw_io.output('DEPS')) |
| 451 | 467 |
| 452 if 'DEPS_interval' in revision_data: | 468 if 'DEPS_interval' in revision_data: |
| 453 for depot_name, interval in revision_data['DEPS_interval'].iteritems(): | 469 for depot_name, interval in revision_data['DEPS_interval'].iteritems(): |
| 454 for item in reversed(interval[:-1]): | 470 for item in reversed(interval[:-1]): |
| 455 step_name = 'Hashing modified DEPS file with revision ' + item | 471 step_name = 'Hashing modified DEPS file with revision ' + item |
| 456 file_hash = 'f412e8458' | 472 file_hash = 'f412e8458' |
| 457 yield api.step_data(step_name, stdout=api.raw_io.output(file_hash)) | 473 yield api.step_data(step_name, stdout=api.raw_io.output(file_hash)) |
| 458 step_name = 'Expanding revision range for revision %s on depot %s' | 474 step_name = 'Expanding revision range for revision %s on depot %s' |
| 459 step_name %= (interval[-1], depot_name) | 475 step_name %= (interval[-1], depot_name) |
| 460 stdout = api.json.output([(r, 0) for r in interval[:-1]]) | 476 stdout = api.json.output([(r, 0) for r in interval[:-1]]) |
| 461 yield api.step_data(step_name, stdout=stdout) | 477 yield api.step_data(step_name, stdout=stdout) |
| 462 | 478 |
| 463 if 'cl_info' in revision_data: | 479 if 'cl_info' in revision_data: |
| 464 step_name = 'Reading culprit cl information.' | 480 step_name = 'Reading culprit cl information.' |
| 465 stdout = api.json.output(revision_data['cl_info']) | 481 stdout = api.json.output(revision_data['cl_info']) |
| 466 yield api.step_data(step_name, stdout=stdout) | 482 yield api.step_data(step_name, stdout=stdout) |
| OLD | NEW |