Chromium Code Reviews| OLD | NEW |
|---|---|
| (Empty) | |
| 1 # Copyright 2016 The Chromium Authors. All rights reserved. | |
| 2 # Use of this source code is governed by a BSD-style license that can be | |
| 3 # found in the LICENSE file. | |
| 4 | |
| 5 from collections import namedtuple | |
| 6 | |
| 7 # TODO(wrengr): We do call this code from various unittests, just not | |
| 8 # from culprit_test.py; so we need to add some extra unittests there. | |
| 9 class Culprit(namedtuple('Culprit', | |
| 10 ['project', 'components', 'cls', 'regression_range', 'algorithm'] | |
| 11 )): # pragma: no cover | |
| 12 """The result of successfully identifying the culprit of a crash report. | |
| 13 | |
| 14 Args: | |
| 15 project (str): the most-suspected project | |
| 16 components (list of str): the suspected crbug components. | |
| 17 cls (list of ??): the suspected CLs. | |
| 18 regression_range (tuple): a pair of the last-good and first-bad versions. | |
| 19 algorithm (str): What algorithm was used to produce this object. | |
| 20 """ | |
| 21 __slots__ = () | |
| 22 | |
| 23 @property | |
| 24 def fields(self): | |
| 25 return self._fields | |
| 26 | |
| 27 # TODO(wrengr): better name for this method. | |
| 28 def ToDicts(self): | |
| 29 """Convert this object to a pair of anonymous dicts for JSON. | |
| 30 | |
| 31 Returns: | |
| 32 (analysis_result_dict, tag_dict) | |
| 33 The analysis result is a dict like below: | |
| 34 { | |
| 35 # Indicate if Findit found any suspects_cls, project, | |
| 36 # components or regression_range. | |
| 37 "found": true, | |
| 38 "suspected_project": "chromium-v8", # Which project is most suspected. | |
| 39 "feedback_url": "https://.." | |
| 40 "suspected_cls": [ | |
| 41 { | |
| 42 "revision": "commit-hash", | |
| 43 "url": "https://chromium.googlesource.com/chromium/src/+/...", | |
| 44 "review_url": "https://codereview.chromium.org/issue-number", | |
| 45 "project_path": "third_party/pdfium", | |
| 46 "author": "who@chromium.org", | |
| 47 "time": "2015-08-17 03:38:16", | |
| 48 "reason": "a plain string with '\n' as line break to expla..." | |
| 49 "reason": [('MinDistance', 1, 'minimum distance is 0.'), | |
| 50 ('TopFrame', 0.9, 'top frame is2nd frame.')], | |
| 51 "changed_files": [ | |
| 52 {"file": "file_name1.cc", | |
| 53 "blame_url": "https://...", | |
| 54 "info": "minimum distance (LOC) 0, frame #2"}, | |
| 55 {"file": "file_name2.cc", | |
| 56 "blame_url": "https://...", | |
| 57 "info": "minimum distance (LOC) 20, frame #4"}, | |
| 58 ... | |
| 59 ], | |
| 60 "confidence": 0.60 | |
| 61 }, | |
| 62 ..., | |
| 63 ], | |
| 64 "regression_range": [ # Detected regression range. | |
| 65 "53.0.2765.0", | |
| 66 "53.0.2766.0" | |
| 67 ], | |
| 68 "suspected_components": [ # A list of crbug components to file bugs. | |
| 69 "Blink>JavaScript" | |
| 70 ] | |
| 71 } | |
| 72 | |
| 73 The code review url might not always be available, because not all | |
| 74 commits go through code review. In that case, commit url should | |
| 75 be used instead. | |
| 76 | |
| 77 The tag dict are allowed key/value pairs to tag the analysis result | |
| 78 for query and monitoring purpose on Findit side. For allowed keys, | |
| 79 please refer to crash_analysis.py and fracas_crash_analysis.py: | |
| 80 For results with normal culprit-finding algorithm: { | |
| 81 'found_suspects': True, | |
| 82 'has_regression_range': True, | |
| 83 'solution': 'core_algorithm', | |
| 84 } | |
| 85 For results using git blame without a regression range: { | |
| 86 'found_suspects': True, | |
| 87 'has_regression_range': False, | |
| 88 'solution': 'blame', | |
| 89 } | |
| 90 If nothing is found: { | |
| 91 'found_suspects': False, | |
| 92 } | |
| 93 """ | |
| 94 # TODO(wrengr): reformulate the JSON stuff so we can drop fields which | |
| 95 # are empty; so that, in turn, we can get rid of the NullCulprit class. | |
| 96 return ( | |
| 97 { | |
| 98 'found': (bool(self.project) or | |
| 99 bool(self.components) or | |
| 100 bool(self.cls) or | |
| 101 bool(self.regression_range)), | |
| 102 'regression_range': self.regression_range, | |
| 103 'suspected_project': self.project, | |
| 104 'suspected_components': self.components, | |
| 105 'suspected_cls': [cl.ToDict() for cl in self.cls], | |
| 106 }, | |
| 107 { | |
| 108 'found_suspects': bool(self.cls), | |
| 109 'found_project': bool(self.project), | |
| 110 'found_components': bool(self.components), | |
| 111 'has_regression_range': bool(self.regression_range), | |
| 112 'solution': self.algorithm, | |
| 113 } | |
| 114 ) | |
| 115 | |
| 116 | |
| 117 # TODO(wrengr): We do call this code from various unittests, just not | |
| 118 # from culprit_test.py; so we need to add some extra unittests there. | |
| 119 class NullCulprit(object): # pragma: no cover | |
|
Sharu Jiang
2016/10/25 18:31:44
How about let NullCulprit inherits Culprit and do
wrengr
2016/10/25 19:49:54
The big question here is whether the JSON encoding
| |
| 120 """The result of failing to identify the culprit of a crash report. | |
| 121 | |
| 122 This class serves as a helper so that we can avoid returning None. It | |
| 123 has all the same properties and methods as the Culprit class, but | |
| 124 returns the empty string, the empty list, or None, as appropriate. The | |
| 125 main difference compared to using Culprit with all those falsy values | |
| 126 is that the result of the ToDicts method is more minimalistic. | |
| 127 | |
| 128 Ideally we'd like to be able to refactor things to avoid the need | |
| 129 for this class. Mostly that means (1) refactoring the unittests to | |
| 130 allow |Findit.FindCulprit| to return None, and (2) reformulating | |
| 131 |Culprit.ToDicts| to create minimal dicts and reformulating the JSON | |
| 132 protocol to support that. | |
| 133 """ | |
| 134 __slots__ = () | |
| 135 | |
| 136 @property | |
| 137 def fields(self): | |
| 138 raise NotImplementedError() | |
| 139 | |
| 140 @property | |
| 141 def project(self): | |
| 142 return '' | |
| 143 | |
| 144 @property | |
| 145 def components(self): | |
| 146 return [] | |
| 147 | |
| 148 @property | |
| 149 def cls(self): | |
| 150 return [] | |
| 151 | |
| 152 @property | |
| 153 def regression_range(self): | |
| 154 # TODO(wrengr): this might should return a pair |(None, None)| | |
| 155 # instead. The desired API isn't fully specified... | |
| 156 return None | |
| 157 | |
| 158 @property | |
| 159 def algorithm(self): | |
| 160 # TODO(wrengr): this might should return the empty string instead. The | |
| 161 # desired API isn't fully specified... | |
| 162 return None | |
| 163 | |
| 164 def ToDicts(self): | |
| 165 return ( | |
| 166 {'found': False}, | |
| 167 {'found_suspects': False, | |
| 168 'has_regression_range': False} | |
| 169 ) | |
| OLD | NEW |