| 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 """An interface for holding state and result of revisions in a bisect job. | 5 """An interface for holding state and result of revisions in a bisect job. |
| 6 | 6 |
| 7 When implementing support for tests other than perf, one should extend this | 7 When implementing support for tests other than perf, one should extend this |
| 8 class so that the bisect module and recipe can use it. | 8 class so that the bisect module and recipe can use it. |
| 9 | 9 |
| 10 See perf_revision_state for an example. | 10 See perf_revision_state for an example. |
| (...skipping 13 matching lines...) Expand all Loading... |
| 24 ( | 24 ( |
| 25 NEW, # A revision_state object that has just been initialized. | 25 NEW, # A revision_state object that has just been initialized. |
| 26 BUILDING, # Requested a build for this revision, waiting for it. | 26 BUILDING, # Requested a build for this revision, waiting for it. |
| 27 TESTING, # A test job for this revision was triggered, waiting for it. | 27 TESTING, # A test job for this revision was triggered, waiting for it. |
| 28 TESTED, # The test job completed with non-failing results. | 28 TESTED, # The test job completed with non-failing results. |
| 29 FAILED, # Either the build or the test jobs failed or timed out. | 29 FAILED, # Either the build or the test jobs failed or timed out. |
| 30 ABORTED, # The build or test job was aborted. (For use in multi-secting). | 30 ABORTED, # The build or test job was aborted. (For use in multi-secting). |
| 31 SKIPPED, # A revision that was not built or tested for a special reason, | 31 SKIPPED, # A revision that was not built or tested for a special reason, |
| 32 # such as those ranges that we know are broken, or when nudging | 32 # such as those ranges that we know are broken, or when nudging |
| 33 # revisions. | 33 # revisions. |
| 34 ) = xrange(7) | 34 NEED_MORE_DATA, # Current number of test values is too small to establish |
| 35 # a statistically significant difference between this |
| 36 # revision and the revisions known to be good and bad. |
| 37 ) = xrange(8) |
| 35 | 38 |
| 36 def __init__(self, revision_string, bisector, | 39 def __init__(self, revision_string, bisector, |
| 37 dependency_depot_name=None, base_revision=None, | 40 dependency_depot_name=None, base_revision=None, |
| 38 deps_revision=None, cp=None): | 41 deps_revision=None, cp=None): |
| 39 """Creates a new instance to track the state of a revision. | 42 """Creates a new instance to track the state of a revision. |
| 40 | 43 |
| 41 There are two use cases for this constructor: | 44 There are two use cases for this constructor: |
| 42 - Creating a revision state for a chromium revision, OR | 45 - Creating a revision state for a chromium revision, OR |
| 43 - Creating a revision state for a chromium revision plus an explicitly | 46 - Creating a revision state for a chromium revision plus an explicitly |
| 44 specified revision of a dependency repository (a DEPS change). | 47 specified revision of a dependency repository (a DEPS change). |
| (...skipping 59 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
| 104 self.commit_pos = cp | 107 self.commit_pos = cp |
| 105 else: # pragma: no cover | 108 else: # pragma: no cover |
| 106 # If there is no commit position, use an abbreviated hash instead. | 109 # If there is no commit position, use an abbreviated hash instead. |
| 107 self.commit_pos = self.commit_hash[:8] | 110 self.commit_pos = self.commit_hash[:8] |
| 108 else: | 111 else: |
| 109 self.commit_hash, self.commit_pos = self._commit_from_rev_string() | 112 self.commit_hash, self.commit_pos = self._commit_from_rev_string() |
| 110 self.build_url = self.bisector.get_platform_gs_prefix() + self._gs_suffix() | 113 self.build_url = self.bisector.get_platform_gs_prefix() + self._gs_suffix() |
| 111 | 114 |
| 112 @property | 115 @property |
| 113 def tested(self): | 116 def tested(self): |
| 114 return self.status in [RevisionState.TESTED] | 117 return self.status in (RevisionState.TESTED,) |
| 115 | 118 |
| 116 @property | 119 @property |
| 117 def in_progress(self): | 120 def in_progress(self): |
| 118 return self.status in (RevisionState.BUILDING, RevisionState.TESTING) | 121 return self.status in (RevisionState.BUILDING, RevisionState.TESTING, |
| 122 RevisionState.NEED_MORE_DATA) |
| 119 | 123 |
| 120 @property | 124 @property |
| 121 def failed(self): | 125 def failed(self): |
| 122 return self.status == RevisionState.FAILED | 126 return self.status == RevisionState.FAILED |
| 123 | 127 |
| 124 @property | 128 @property |
| 125 def aborted(self): | 129 def aborted(self): |
| 126 return self.status == RevisionState.ABORTED | 130 return self.status == RevisionState.ABORTED |
| 127 | 131 |
| 128 @property | 132 @property |
| (...skipping 12 matching lines...) Expand all Loading... |
| 141 def bad(self, value): | 145 def bad(self, value): |
| 142 self._good = not value | 146 self._good = not value |
| 143 | 147 |
| 144 def start_job(self): | 148 def start_job(self): |
| 145 """Starts a build, or a test job if the build is available.""" | 149 """Starts a build, or a test job if the build is available.""" |
| 146 if self.status == RevisionState.NEW and not self._is_build_archived(): | 150 if self.status == RevisionState.NEW and not self._is_build_archived(): |
| 147 self._request_build() | 151 self._request_build() |
| 148 self.status = RevisionState.BUILDING | 152 self.status = RevisionState.BUILDING |
| 149 return | 153 return |
| 150 | 154 |
| 151 if self._is_build_archived() and self.status in [RevisionState.NEW, | 155 if self._is_build_archived() and self.status in ( |
| 152 RevisionState.BUILDING]: | 156 RevisionState.NEW, RevisionState.BUILDING, |
| 157 RevisionState.NEED_MORE_DATA): |
| 153 self._do_test() | 158 self._do_test() |
| 154 self.status = RevisionState.TESTING | 159 self.status = RevisionState.TESTING |
| 155 | 160 |
| 156 def abort(self): # pragma: no cover | 161 def abort(self): # pragma: no cover |
| 157 """Aborts the job. | 162 """Aborts the job. |
| 158 | 163 |
| 159 This method is typically called when the bisect no longer requires it. Such | 164 This method is typically called when the bisect no longer requires it. Such |
| 160 as when a later good revision or an earlier bad revision have been found in | 165 as when a later good revision or an earlier bad revision have been found in |
| 161 parallel. | 166 parallel. |
| 162 """ | 167 """ |
| (...skipping 77 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
| 240 """Checks on the pending jobs and updates status accordingly. | 245 """Checks on the pending jobs and updates status accordingly. |
| 241 | 246 |
| 242 This method will check for the build to complete and then trigger the test, | 247 This method will check for the build to complete and then trigger the test, |
| 243 or will wait for the test as appropriate. | 248 or will wait for the test as appropriate. |
| 244 | 249 |
| 245 To wait for the test we try to get the buildbot job url from GS, and if | 250 To wait for the test we try to get the buildbot job url from GS, and if |
| 246 available, we query the status of such job. | 251 available, we query the status of such job. |
| 247 """ | 252 """ |
| 248 if self.status == RevisionState.BUILDING and self._is_build_archived(): | 253 if self.status == RevisionState.BUILDING and self._is_build_archived(): |
| 249 self.start_job() | 254 self.start_job() |
| 250 elif self.status == RevisionState.TESTING and self._results_available(): | 255 elif (self.status in (RevisionState.TESTING, RevisionState.NEED_MORE_DATA) |
| 251 self._read_test_results() | 256 and self._results_available()): |
| 257 # If we have already decided whether the revision is good or bad we |
| 258 # shouldn't check again |
| 259 check_revision_goodness = not(self.good or self.bad) |
| 260 self._read_test_results( |
| 261 check_revision_goodness=check_revision_goodness) |
| 252 # We assume _read_test_results may have changed the status to a broken | 262 # We assume _read_test_results may have changed the status to a broken |
| 253 # state such as FAILED or ABORTED. | 263 # state such as FAILED or ABORTED. |
| 254 if self.status == RevisionState.TESTING: | 264 if self.status in (RevisionState.TESTING, RevisionState.NEED_MORE_DATA): |
| 255 self.status = RevisionState.TESTED | 265 self.status = RevisionState.TESTED |
| 256 | 266 |
| 257 def _is_build_archived(self): | 267 def _is_build_archived(self): |
| 258 """Checks if the revision is already built and archived.""" | 268 """Checks if the revision is already built and archived.""" |
| 259 if not self.build_archived: | 269 if not self.build_archived: |
| 260 api = self.bisector.api | 270 api = self.bisector.api |
| 261 self.build_archived = api.gsutil_file_exists(self.build_url) | 271 self.build_archived = api.gsutil_file_exists(self.build_url) |
| 262 | 272 |
| 263 if self.bisector.dummy_builds: | 273 if self.bisector.dummy_builds: |
| 264 self.build_archived = self.in_progress | 274 self.build_archived = self.in_progress |
| (...skipping 59 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
| 324 | 334 |
| 325 def _get_hash_from_pos(self, pos): | 335 def _get_hash_from_pos(self, pos): |
| 326 api = self.bisector.api | 336 api = self.bisector.api |
| 327 try: | 337 try: |
| 328 result = api.m.commit_position.chromium_hash_from_commit_position(pos) | 338 result = api.m.commit_position.chromium_hash_from_commit_position(pos) |
| 329 except api.m.step.StepFailure as sf: # pragma: no cover | 339 except api.m.step.StepFailure as sf: # pragma: no cover |
| 330 self.bisector.surface_result('BAD_REV') | 340 self.bisector.surface_result('BAD_REV') |
| 331 api.m.halt('Failed to resolve commit position - ' + sf.reason) | 341 api.m.halt('Failed to resolve commit position - ' + sf.reason) |
| 332 raise | 342 raise |
| 333 return result | 343 return result |
| OLD | NEW |