Chromium Code Reviews
chromiumcodereview-hr@appspot.gserviceaccount.com (chromiumcodereview-hr) | Please choose your nickname with Settings | Help | Chromium Project | Gerrit Changes | Sign out
(140)

Side by Side Diff: scripts/slave/recipe_modules/auto_bisect/revision_state.py

Issue 2274763002: Use buildbucket to assess build failure. (Closed) Base URL: https://chromium.googlesource.com/chromium/tools/build.git@master
Patch Set: Created 4 years, 4 months ago
Use n/p to move between diff chunks; N/P to move between comments. Draft comments are only viewable by you.
Jump to:
View unified diff | Download patch
OLDNEW
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.
11 """ 11 """
12 12
13 import hashlib 13 import hashlib
14 import json 14 import json
15 import math 15 import math
16 import os 16 import os
17 import tempfile 17 import tempfile
18 import re 18 import re
19 import uuid 19 import uuid
20 20
21 from . import depot_config 21 from . import depot_config
22 22
23 # These relate to how to increase the number of repetitions during re-test 23 # These relate to how to increase the number of repetitions during re-test
24 MINIMUM_SAMPLE_SIZE = 5 24 MINIMUM_SAMPLE_SIZE = 5
25 INCREASE_FACTOR = 1.5 25 INCREASE_FACTOR = 1.5
26 # Buildbot job result codes.
27 # See http://docs.buildbot.net/current/developer/results.html
28 SUCCESS, WARNINGS, FAILURE, SKIPPED, EXCEPTION = range(5)
29 26
30 class RevisionState(object): 27 class RevisionState(object):
31 """Abstracts the state of a single revision on a bisect job.""" 28 """Abstracts the state of a single revision on a bisect job."""
32 29
33 # Possible values for the status attribute of RevisionState: 30 # Possible values for the status attribute of RevisionState:
34 ( 31 (
35 NEW, # A revision_state object that has just been initialized. 32 NEW, # A revision_state object that has just been initialized.
36 BUILDING, # Requested a build for this revision, waiting for it. 33 BUILDING, # Requested a build for this revision, waiting for it.
37 TESTING, # A test job for this revision was triggered, waiting for it. 34 TESTING, # A test job for this revision was triggered, waiting for it.
38 TESTED, # The test job completed with non-failing results. 35 TESTED, # The test job completed with non-failing results.
(...skipping 30 matching lines...) Expand all
69 self.previous_revision = None 66 self.previous_revision = None
70 self.job_name = None 67 self.job_name = None
71 self.patch_file = None 68 self.patch_file = None
72 self.deps_revision = None 69 self.deps_revision = None
73 self.depot_name = depot_name or self.bisector.base_depot 70 self.depot_name = depot_name or self.bisector.base_depot
74 self.depot = depot_config.DEPOT_DEPS_NAME[self.depot_name] 71 self.depot = depot_config.DEPOT_DEPS_NAME[self.depot_name]
75 self.commit_hash = str(commit_hash) 72 self.commit_hash = str(commit_hash)
76 self._rev_str = None 73 self._rev_str = None
77 self.base_revision = base_revision 74 self.base_revision = base_revision
78 self.revision_overrides = {} 75 self.revision_overrides = {}
76 self.build_id = None
79 if self.base_revision: 77 if self.base_revision:
80 assert self.base_revision.deps_file_contents 78 assert self.base_revision.deps_file_contents
81 self.needs_patch = True 79 self.needs_patch = True
82 self.revision_overrides[self.depot['src']] = self.commit_hash 80 self.revision_overrides[self.depot['src']] = self.commit_hash
83 self.deps_patch, self.deps_file_contents = self.bisector.make_deps_patch( 81 self.deps_patch, self.deps_file_contents = self.bisector.make_deps_patch(
84 self.base_revision, self.base_revision.deps_file_contents, 82 self.base_revision, self.base_revision.deps_file_contents,
85 self.depot, self.commit_hash) 83 self.depot, self.commit_hash)
86 self.deps_sha = hashlib.sha1(self.deps_patch).hexdigest() 84 self.deps_sha = hashlib.sha1(self.deps_patch).hexdigest()
87 self.deps_sha_patch = self.bisector.make_deps_sha_file(self.deps_sha) 85 self.deps_sha_patch = self.bisector.make_deps_sha_file(self.deps_sha)
88 self.deps = dict(base_revision.deps) 86 self.deps = dict(base_revision.deps)
89 self.deps[self.depot_name] = self.commit_hash 87 self.deps[self.depot_name] = self.commit_hash
90 else: 88 else:
91 self.needs_patch = False 89 self.needs_patch = False
92 self.build_url = self.bisector.get_platform_gs_prefix() + self._gs_suffix() 90 self.build_url = self.bisector.get_platform_gs_prefix() + self._gs_suffix()
93 self.values = [] 91 self.values = []
94 self.mean_value = None 92 self.mean_value = None
95 self.overall_return_code = None 93 self.overall_return_code = None
96 self.std_dev = None 94 self.std_dev = None
97 self._test_config = None 95 self._test_config = None
98 self.build_number = None
99 96
100 if self.bisector.test_type == 'perf': 97 if self.bisector.test_type == 'perf':
101 self.repeat_count = MINIMUM_SAMPLE_SIZE 98 self.repeat_count = MINIMUM_SAMPLE_SIZE
102 else: 99 else:
103 self.repeat_count = self.bisector.bisect_config.get( 100 self.repeat_count = self.bisector.bisect_config.get(
104 'repeat_count', MINIMUM_SAMPLE_SIZE) 101 'repeat_count', MINIMUM_SAMPLE_SIZE)
105 102
106 @property 103 @property
107 def tested(self): 104 def tested(self):
108 return self.status in (RevisionState.TESTED,) 105 return self.status in (RevisionState.TESTED,)
(...skipping 167 matching lines...) Expand 10 before | Expand all | Expand 10 after
276 """Checks if the revision is already built and archived.""" 273 """Checks if the revision is already built and archived."""
277 if not self.build_archived: 274 if not self.build_archived:
278 api = self.bisector.api 275 api = self.bisector.api
279 self.build_archived = api.gsutil_file_exists(self.build_url) 276 self.build_archived = api.gsutil_file_exists(self.build_url)
280 277
281 if self.bisector.dummy_builds: 278 if self.bisector.dummy_builds:
282 self.build_archived = self.in_progress 279 self.build_archived = self.in_progress
283 280
284 return self.build_archived 281 return self.build_archived
285 282
286 def _fetch_build_info(self, base_url, build_number):
287 api = self.bisector.api
288 build_url = '%s/builds/%s?as_text=1' % (base_url, build_number)
289 fetch_result = api.m.url.fetch( build_url, step_name='fetch build details')
290 return json.loads(fetch_result or '{}')
291
292 def _is_build_failed(self): 283 def _is_build_failed(self):
293 api = self.bisector.api 284 result = self.bisector.api.m.buildbucket.get_build(
294 current_build = None 285 self.build_id,
295 path = 'json/builders/' + self.bisector.get_builder_bot_for_this_platform() 286 step_test_data=lambda: self.bisector.api.m.json.test_api.output_stream(
296 base_url = api.m.properties.get('buildbotURL', 'http://localhost:8041/') 287 {'results': [
297 base_url += path 288 {'build': {'result': 'SUCCESS', 'status': 'COMPLETED'}}]}
298 if self.build_number is None: 289 ))
299 try: 290 return (result.stdout['results'][0]['build']['status'] == 'COMPLETED' and
300 # Get all the current builds. 291 result.stdout['results'][0]['build'].get('result') != 'SUCCESS')
301 builder_state_url = base_url + '?as_text=1'
302 builder_state = api.m.url.fetch(
303 builder_state_url, step_name='fetch builder state')
304 builder_state = json.loads(builder_state or '{}')
305 for build_number in builder_state.get('cachedBuilds', []):
306 build = self._fetch_build_info(base_url, build_number)
307 # Properties is a list of triples (key, value, source)
308 build_properties = dict([t[:2] for t in build.get('properties', [])])
309 if build_properties.get('build_archive_url') == self.build_url:
310 self.build_number = build_number
311 current_build = build
312 break
313 except (api.m.step.StepFailure, ValueError): # pragma: no cover
314 # If we cannot get json from buildbot, we cannot determine if a build is
315 # failed, hence we consider it in progress until it times out.
316 return False
317 if self.build_number is None:
318 # The build hasn't started yet, therefore it's not failed.
319 return False
320 if not current_build:
321 current_build = self._fetch_build_info(base_url, self.build_number)
322 return current_build.get('results') in [FAILURE, SKIPPED, EXCEPTION]
323 292
324 def _results_available(self): 293 def _results_available(self):
325 """Checks if the results for the test job have been uploaded.""" 294 """Checks if the results for the test job have been uploaded."""
326 api = self.bisector.api 295 api = self.bisector.api
327 result = api.gsutil_file_exists(self.test_results_url) 296 result = api.gsutil_file_exists(self.test_results_url)
328 if self.bisector.dummy_builds: 297 if self.bisector.dummy_builds:
329 return self.in_progress 298 return self.in_progress
330 return result # pragma: no cover 299 return result # pragma: no cover
331 300
332 def _gs_suffix(self): 301 def _gs_suffix(self):
(...skipping 87 matching lines...) Expand 10 before | Expand all | Expand 10 after
420 'build_archive_url': self.build_url, 389 'build_archive_url': self.build_url,
421 }, 390 },
422 }, 391 },
423 'client_operation_id': operation_id 392 'client_operation_id': operation_id
424 } 393 }
425 if self.revision_overrides: 394 if self.revision_overrides:
426 build_details['parameters']['properties']['deps_revision_overrides'] = \ 395 build_details['parameters']['properties']['deps_revision_overrides'] = \
427 self.revision_overrides 396 self.revision_overrides
428 397
429 try: 398 try:
430 api.m.buildbucket.put([build_details], 399 result = api.m.buildbucket.put(
431 api.m.service_account.get_json_path( 400 [build_details],
432 api.SERVICE_ACCOUNT)) 401 api.m.service_account.get_json_path(api.SERVICE_ACCOUNT),
402 step_test_data=lambda: api.m.json.test_api.output_stream(
403 {'results':[{'build':{'id':'1201331270'}}]}))
433 except api.m.step.StepFailure: # pragma: no cover 404 except api.m.step.StepFailure: # pragma: no cover
434 self.bisector.surface_result('BUILD_FAILURE') 405 self.bisector.surface_result('BUILD_FAILURE')
435 raise 406 raise
407 self.build_id = result.stdout['results'][0]['build']['id']
436 408
437 def _get_bisect_config_for_tester(self): 409 def _get_bisect_config_for_tester(self):
438 """Copies the key-value pairs required by a tester bot to a new dict.""" 410 """Copies the key-value pairs required by a tester bot to a new dict."""
439 result = {} 411 result = {}
440 required_test_properties = { 412 required_test_properties = {
441 'truncate_percent', 413 'truncate_percent',
442 'metric', 414 'metric',
443 'command', 415 'command',
444 'test_type' 416 'test_type'
445 } 417 }
(...skipping 153 matching lines...) Expand 10 before | Expand all | Expand 10 after
599 else: 571 else:
600 next_revision_to_test.retest() 572 next_revision_to_test.retest()
601 573
602 def __repr__(self): 574 def __repr__(self):
603 if self.overall_return_code is not None: 575 if self.overall_return_code is not None:
604 return ('RevisionState(rev=%s, values=%r, overall_return_code=%r, ' 576 return ('RevisionState(rev=%s, values=%r, overall_return_code=%r, '
605 'std_dev=%r)') % (self.revision_string(), self.values, 577 'std_dev=%r)') % (self.revision_string(), self.values,
606 self.overall_return_code, self.std_dev) 578 self.overall_return_code, self.std_dev)
607 return ('RevisionState(rev=%s, values=%r, mean_value=%r, std_dev=%r)' % ( 579 return ('RevisionState(rev=%s, values=%r, mean_value=%r, std_dev=%r)' % (
608 self.revision_string(), self.values, self.mean_value, self.std_dev)) 580 self.revision_string(), self.values, self.mean_value, self.std_dev))
OLDNEW

Powered by Google App Engine
This is Rietveld 408576698