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

Side by Side Diff: appengine/findit/crash/findit.py

Issue 2673993003: [Predator] Pass config as argument to findit. (Closed)
Patch Set: Created 3 years, 10 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 2016 The Chromium Authors. All rights reserved. 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 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 copy 5 import copy
6 import json 6 import json
7 import logging 7 import logging
8 8
9 from google.appengine.ext import ndb 9 from google.appengine.ext import ndb
10 10
11 from common import appengine_util 11 from common import appengine_util
12 from common.chrome_dependency_fetcher import ChromeDependencyFetcher 12 from common.chrome_dependency_fetcher import ChromeDependencyFetcher
13 from common import constants 13 from common import constants
14 from crash.component import Component
15 from crash.component_classifier import ComponentClassifier
14 from crash.crash_report import CrashReport 16 from crash.crash_report import CrashReport
17 from crash.project import Project
18 from crash.project_classifier import ProjectClassifier
15 from libs import time_util 19 from libs import time_util
16 from model import analysis_status 20 from model import analysis_status
17 from model.crash.crash_config import CrashConfig 21 from model.crash.crash_config import CrashConfig
18 22
19 23
20 # TODO(http://crbug.com/659346): since most of our unit tests are 24 # TODO(http://crbug.com/659346): since most of our unit tests are
21 # FinditForFracas-specific, wrengr moved them to findit_for_chromecrash_test.py. 25 # FinditForFracas-specific, wrengr moved them to findit_for_chromecrash_test.py.
22 # However, now we're missing coverage for most of this file (due to the 26 # However, now we're missing coverage for most of this file (due to the
23 # buggy way coverage is computed). Need to add a bunch of new unittests 27 # buggy way coverage is computed). Need to add a bunch of new unittests
24 # to get coverage back up. 28 # to get coverage back up.
25 29
26 # TODO: this class depends on ndb stuff, and should therefore move to 30 # TODO: this class depends on ndb stuff, and should therefore move to
27 # cr-culprit-finder/service/predator as part of the big reorganization. 31 # cr-culprit-finder/service/predator as part of the big reorganization.
28 # This class should be renamed to avoid confustion between Findit and Predator. 32 # This class should be renamed to avoid confustion between Findit and Predator.
29 # Think of a good name (e.g.'PredatorApp') for this class. 33 # Think of a good name (e.g.'PredatorApp') for this class.
30 class Findit(object): 34 class Findit(object):
31 35
32 def __init__(self, get_repository): 36 def __init__(self, get_repository, config):
33 """ 37 """
34 Args: 38 Args:
35 get_repository (callable): a function from DEP urls to ``Repository`` 39 get_repository (callable): a function from DEP urls to ``Repository``
36 objects, so we can get changelogs and blame for each dep. Notably, 40 objects, so we can get changelogs and blame for each dep. Notably,
37 to keep the code here generic, we make no assumptions about 41 to keep the code here generic, we make no assumptions about
38 which subclass of ``Repository`` this function returns. Thus, 42 which subclass of ``Repository`` this function returns. Thus,
39 it is up to the caller to decide what class to return and handle 43 it is up to the caller to decide what class to return and handle
40 any other arguments that class may require (e.g., an http client 44 any other arguments that class may require (e.g., an http client
41 for ``GitilesRepository``). 45 for ``GitilesRepository``).
chanli 2017/02/03 23:58:50 nit: add docstring for config
Sharu Jiang 2017/02/10 23:07:38 Done.
42 """ 46 """
43 self._get_repository = get_repository 47 self._get_repository = get_repository
44 self._dep_fetcher = ChromeDependencyFetcher(get_repository) 48 self._dep_fetcher = ChromeDependencyFetcher(get_repository)
49
50 project_classifier_config = config.project_classifier
51 projects = [Project(name, path_regexs, function_regexs, host_directories)
52 for name, path_regexs, function_regexs, host_directories
53 in project_classifier_config['project_path_function_hosts']]
54 self._project_classifier = ProjectClassifier(
55 projects, project_classifier_config['top_n'],
56 project_classifier_config['non_chromium_project_rank_priority'])
57
58 component_classifier_config = config.component_classifier
59 components = [Component(component_name, path_regex, function_regex)
60 for path_regex, function_regex, component_name
61 in component_classifier_config['path_function_component']]
62 self._component_classifier = ComponentClassifier(
63 components, component_classifier_config['top_n'])
64
65 self._config = config
66
45 # TODO(http://crbug.com/659354): because self.client is volatile, 67 # TODO(http://crbug.com/659354): because self.client is volatile,
46 # we need some way of updating the Predator instance whenever the 68 # we need some way of updating the Predator instance whenever the
47 # config changes. How to do that cleanly? 69 # config changes. How to do that cleanly?
48 self._predator = None 70 self._predator = None
49 self._stacktrace_parser = None 71 self._stacktrace_parser = None
50 72
51 # This is a class method because it should be the same for all 73 # This is a class method because it should be the same for all
52 # instances of this class. We can in fact call class methods on 74 # instances of this class. We can in fact call class methods on
53 # instances (not just on the class itself), so we could in principle 75 # instances (not just on the class itself), so we could in principle
54 # get by with just this method. However, a @classmethod is treated 76 # get by with just this method. However, a @classmethod is treated
(...skipping 25 matching lines...) Expand all
80 102
81 N.B., this property is static and should not be overridden.""" 103 N.B., this property is static and should not be overridden."""
82 return self._ClientID() 104 return self._ClientID()
83 105
84 # TODO(http://crbug.com/659354): can we remove the dependency on 106 # TODO(http://crbug.com/659354): can we remove the dependency on
85 # CrashConfig entirely? It'd be better to receive method calls 107 # CrashConfig entirely? It'd be better to receive method calls
86 # whenever things change, so that we know the change happened (and 108 # whenever things change, so that we know the change happened (and
87 # what in particular changed) so that we can update our internal state 109 # what in particular changed) so that we can update our internal state
88 # as appropriate. 110 # as appropriate.
89 @property 111 @property
90 def config(self): 112 def client_config(self):
91 """Get the current value of the client config for the class of this object. 113 """Get the current value of the client config for the class of this object.
92 114
93 N.B., this property is volatile and may change asynchronously. 115 N.B., this property is volatile and may change asynchronously.
94 116
95 If the event of an error this method will return ``None``. That we do 117 If the event of an error this method will return ``None``. That we do
96 not return the empty dict is intentional. All of the circumstances 118 not return the empty dict is intentional. All of the circumstances
97 which would lead to this method returning ``None`` indicate 119 which would lead to this method returning ``None`` indicate
98 underlying bugs in code elsewhere. (E.g., creating instances of 120 underlying bugs in code elsewhere. (E.g., creating instances of
99 abstract classes, implementing a subclass which is not suppported by 121 abstract classes, implementing a subclass which is not suppported by
100 ``CrashConfig``, etc.) Because we return ``None``, any subsequent 122 ``CrashConfig``, etc.) Because we return ``None``, any subsequent
101 calls to ``__getitem__`` or ``get`` will raise method-missing errors; 123 calls to ``__getitem__`` or ``get`` will raise method-missing errors;
102 which serve to highlight the underlying bug. Whereas, if we silently 124 which serve to highlight the underlying bug. Whereas, if we silently
103 returned the empty dict, then calls to ``get`` would "work" just 125 returned the empty dict, then calls to ``get`` would "work" just
104 fine; thereby masking the underlying bug! 126 fine; thereby masking the underlying bug!
105 """ 127 """
106 return CrashConfig.Get().GetClientConfig(self.client_id) 128 return self._config.GetClientConfig(self.client_id)
107 129
108 # TODO(http://crbug.com/644476): rename to CanonicalizePlatform or 130 # TODO(http://crbug.com/644476): rename to CanonicalizePlatform or
109 # something like that. 131 # something like that.
110 def RenamePlatform(self, platform): 132 def RenamePlatform(self, platform):
111 """Remap the platform to a different one, based on the config.""" 133 """Remap the platform to a different one, based on the config."""
112 # TODO(katesonia): Remove the default value after adding validity check to 134 # TODO(katesonia): Remove the default value after adding validity check to
113 # config. 135 # config.
114 return self.config.get('platform_rename', {}).get(platform, platform) 136 return self.client_config.get('platform_rename', {}).get(platform, platform)
115 137
116 def CheckPolicy(self, crash_data): # pylint: disable=W0613 138 def CheckPolicy(self, crash_data): # pylint: disable=W0613
117 """Check whether this client supports analyzing the given report. 139 """Check whether this client supports analyzing the given report.
118 140
119 Some clients only support analysis for crashes on certain platforms 141 Some clients only support analysis for crashes on certain platforms
120 or channels, etc. This method checks to see whether this client can 142 or channels, etc. This method checks to see whether this client can
121 analyze the given crash. The default implementation on the Findit 143 analyze the given crash. The default implementation on the Findit
122 base class returns None for everything, so that unsupported clients 144 base class returns None for everything, so that unsupported clients
123 reject everything, as expected. 145 reject everything, as expected.
124 146
(...skipping 82 matching lines...) Expand 10 before | Expand all | Expand 10 after
207 def ParseStacktrace(self, model): # pragma: no cover 229 def ParseStacktrace(self, model): # pragma: no cover
208 """Parse a CrashAnalysis's ``stack_trace`` string into a Stacktrace object. 230 """Parse a CrashAnalysis's ``stack_trace`` string into a Stacktrace object.
209 231
210 Args: 232 Args:
211 model (CrashAnalysis): The model containing the stack_trace string 233 model (CrashAnalysis): The model containing the stack_trace string
212 to be parsed. 234 to be parsed.
213 235
214 Returns: 236 Returns:
215 On success, returns a Stacktrace object; on failure, returns None. 237 On success, returns a Stacktrace object; on failure, returns None.
216 """ 238 """
217 # Use up-to-date ``top_n`` in self.config to filter top n frames. 239 # Use up-to-date ``top_n`` in self.client_config to filter top n frames.
218 stacktrace = self._stacktrace_parser.Parse( 240 stacktrace = self._stacktrace_parser.Parse(
219 model.stack_trace, 241 model.stack_trace,
220 self._dep_fetcher.GetDependency(model.crashed_version, model.platform), 242 self._dep_fetcher.GetDependency(model.crashed_version, model.platform),
221 model.signature, 243 model.signature,
222 self.config.get('top_n')) 244 self.client_config.get('top_n'))
223 if not stacktrace: 245 if not stacktrace:
224 logging.warning('Failed to parse the stacktrace %s', model.stack_trace) 246 logging.warning('Failed to parse the stacktrace %s', model.stack_trace)
225 return None 247 return None
226 248
227 return stacktrace 249 return stacktrace
228 250
229 def ProcessResultForPublishing(self, result, key): 251 def ProcessResultForPublishing(self, result, key):
230 """Client specific processing of result data for publishing.""" 252 """Client specific processing of result data for publishing."""
231 raise NotImplementedError() 253 raise NotImplementedError()
232 254
(...skipping 39 matching lines...) Expand 10 before | Expand all | Expand 10 after
272 stacktrace = self.ParseStacktrace(model) 294 stacktrace = self.ParseStacktrace(model)
273 if stacktrace is None: 295 if stacktrace is None:
274 return None 296 return None
275 297
276 return self._predator.FindCulprit(CrashReport( 298 return self._predator.FindCulprit(CrashReport(
277 crashed_version = model.crashed_version, 299 crashed_version = model.crashed_version,
278 signature = model.signature, 300 signature = model.signature,
279 platform = model.platform, 301 platform = model.platform,
280 stacktrace = stacktrace, 302 stacktrace = stacktrace,
281 regression_range = model.regression_range)) 303 regression_range = model.regression_range))
OLDNEW
« no previous file with comments | « appengine/findit/crash/crash_pipeline.py ('k') | appengine/findit/crash/findit_for_chromecrash.py » ('j') | no next file with comments »

Powered by Google App Engine
This is Rietveld 408576698