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

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

Issue 2663063007: [Predator] Switch from anonymous dict to CrashData. (Closed)
Patch Set: Rebase and fix delta test. 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 mock 5 import mock
6 6
7 from common import chrome_dependency_fetcher 7 from common import chrome_dependency_fetcher
8 from common.dependency import DependencyRoll 8 from common.dependency import DependencyRoll
9 from crash import chromecrash_parser 9 from crash import chromecrash_parser
10 from crash import detect_regression_range 10 from crash import detect_regression_range
(...skipping 30 matching lines...) Expand all
41 41
42 @classmethod 42 @classmethod
43 def _ClientID(cls): # pragma: no cover 43 def _ClientID(cls): # pragma: no cover
44 """Avoid throwing a NotImplementedError. 44 """Avoid throwing a NotImplementedError.
45 45
46 Since this method is called from ``FinditForChromeCrash.__init__`` 46 Since this method is called from ``FinditForChromeCrash.__init__``
47 in order to construct the Azalea object, we need to not throw 47 in order to construct the Azalea object, we need to not throw
48 exceptions since we want to be able to test the FinditForChromeCrash 48 exceptions since we want to be able to test the FinditForChromeCrash
49 class itself. 49 class itself.
50 """ 50 """
51 return 'fracas' 51 return 'ChromeCrash'
52
53 @property
54 def client_config(self):
55 """Avoid returning None.
56
57 The default ``Findit.client_config`` will return None if the client
58 id is not found in the CrashConfig. This in turn will cause
59 ``FinditForChromeCrash.__init__`` to crash, since NoneType doesn't
60 have a ``get`` method. In general it's fine for things to crash, since
61 noone should make instances of Findit subclasses which don't define
62 ``_clientID``; but for this test suite, we want to permit instances
63 of FinditForChromeCrash, so that we can test that class directly.
64 """
65 return {}
66 52
67 53
68 def _FinditForFracas(config=None): 54 def _FinditForFracas(config=None):
69 """A helper to pass in the standard pipeline class.""" 55 """A helper to pass in the standard pipeline class."""
70 return FinditForFracas(MOCK_GET_REPOSITORY, config or {}) 56 return FinditForFracas(MOCK_GET_REPOSITORY, config or {})
71 57
72 58
73 class FinditForChromeCrashTest(PredatorTestCase): 59 class FinditForChromeCrashTest(PredatorTestCase):
74 60
75 # TODO(wrengr): what was the purpose of this test? As written it's 61 # TODO(wrengr): what was the purpose of this test? As written it's
76 # just testing that mocking works. I'm guessing it was to check that 62 # just testing that mocking works. I'm guessing it was to check that
77 # we fail when the analysis is for the wrong client_id; but if so, 63 # we fail when the analysis is for the wrong client_id; but if so,
78 # then we shouldn't need to mock FindCulprit... 64 # then we shouldn't need to mock FindCulprit...
79 def testFindCulprit(self): 65 def testFindCulprit(self):
80 self.mock(FinditForChromeCrash, 'FindCulprit', lambda self, *_: None) 66 self.mock(FinditForChromeCrash, 'FindCulprit', lambda self, *_: None)
81 67
82 # TODO(wrengr): would be less fragile to call 68 # TODO(wrengr): would be less fragile to call
83 # FinditForFracas.CreateAnalysis instead; though if I'm right about 69 # FinditForFracas.CreateAnalysis instead; though if I'm right about
84 # the original purpose of this test, then this is one of the few 70 # the original purpose of this test, then this is one of the few
85 # places where calling FracasCrashAnalysis directly would actually 71 # places where calling FracasCrashAnalysis directly would actually
86 # make sense. 72 # make sense.
87 analysis = FracasCrashAnalysis.Create({'signature': 'sig'}) 73 analysis = FracasCrashAnalysis.Create({'signature': 'sig'})
88 # TODO(wrengr): shouldn't FracasCrashAnalysis.Create already have set
89 # the client_id?
90 analysis.client_id = CrashClient.FRACAS
91
92 findit_client = _FinditForChromeCrash( 74 findit_client = _FinditForChromeCrash(
93 GitilesRepository.Factory(HttpClientAppengine()), 75 GitilesRepository.Factory(HttpClientAppengine()), CrashConfig.Get())
94 config=CrashConfig.Get())
95 self.assertIsNone(findit_client.FindCulprit(analysis)) 76 self.assertIsNone(findit_client.FindCulprit(analysis))
96 77
97 78
98 class FinditForFracasTest(PredatorTestCase): 79 class FinditForFracasTest(PredatorTestCase):
99 80
100 def setUp(self): 81 def setUp(self):
101 super(FinditForFracasTest, self).setUp() 82 super(FinditForFracasTest, self).setUp()
102 self.findit = _FinditForFracas(config=CrashConfig.Get()) 83 self._client = _FinditForFracas(config=CrashConfig.Get())
103 84
104 def testPlatformRename(self): 85 def testCheckPolicyBlacklistSignature(self):
105 self.assertEqual(self.findit.RenamePlatform('linux'), 'unix') 86 raw_crash_data = self.GetDummyChromeCrashData(
87 client_id = CrashClient.FRACAS,
88 signature='Blacklist marker signature')
89 crash_data = self._client.GetCrashData(raw_crash_data)
90 self.assertFalse(self._client._CheckPolicy(crash_data))
106 91
107 def testCheckPolicyUnsupportedPlatform(self): 92 def testCheckPolicyUnsupportedPlatform(self):
108 self.assertIsNone(self.findit.CheckPolicy(self.GetDummyCrashData( 93 raw_crash_data = self.GetDummyChromeCrashData(
109 platform = 'unsupported_platform'))) 94 client_id = CrashClient.FRACAS,
95 platform='unsupported_platform')
96 crash_data = self._client.GetCrashData(raw_crash_data)
97 self.assertFalse(self._client._CheckPolicy(crash_data))
110 98
111 def testCheckPolicyBlacklistedSignature(self): 99 def testScheduleNewAnalysisSkipsUnsupportedChannel(self):
112 self.assertIsNone(self.findit.CheckPolicy(self.GetDummyCrashData( 100 raw_crash_data = self.GetDummyChromeCrashData(
113 signature = 'Blacklist marker signature'))) 101 client_id = CrashClient.FRACAS,
102 channel='unsupported_channel')
103 crash_data = self._client.GetCrashData(raw_crash_data)
104 self.assertFalse(self._client._CheckPolicy(crash_data))
114 105
115 def testCheckPolicyPlatformRename(self): 106 def testCheckPolicySuccess(self):
116 new_crash_data = self.findit.CheckPolicy(self.GetDummyCrashData( 107 crash_data = self._client.GetCrashData(self.GetDummyChromeCrashData(
117 platform = 'linux')) 108 client_id = CrashClient.FRACAS))
118 self.assertIsNotNone(new_crash_data, 109 self.assertTrue(self._client._CheckPolicy(crash_data))
119 'FinditForFracas.CheckPolicy unexpectedly returned None')
120 self.assertEqual(new_crash_data['platform'], 'unix')
121 110
122 def testCreateAnalysis(self): 111 def testCreateAnalysis(self):
123 self.assertIsNotNone(self.findit.CreateAnalysis( 112 self.assertIsNotNone(self._client.CreateAnalysis(
124 {'signature': 'sig'})) 113 {'signature': 'sig'}))
125 114
126 def testGetAnalysis(self): 115 def testGetAnalysis(self):
127 crash_identifiers = {'signature': 'sig'} 116 crash_identifiers = {'signature': 'sig'}
128 # TODO(wrengr): would be less fragile to call 117 # TODO(wrengr): would be less fragile to call
129 # FinditForFracas.CreateAnalysis instead. 118 # FinditForFracas.CreateAnalysis instead.
130 analysis = FracasCrashAnalysis.Create(crash_identifiers) 119 analysis = FracasCrashAnalysis.Create(crash_identifiers)
131 analysis.put() 120 analysis.put()
132 self.assertEqual(self.findit.GetAnalysis(crash_identifiers), 121 self.assertEqual(self._client.GetAnalysis(crash_identifiers), analysis)
133 analysis)
134
135 def testInitializeAnalysisForFracas(self):
136 crash_data = self.GetDummyCrashData(platform = 'linux')
137 crash_identifiers = crash_data['crash_identifiers']
138
139 self.findit = self.findit
140 analysis = self.findit.CreateAnalysis(crash_identifiers)
141 self.findit._InitializeAnalysis(analysis, crash_data)
142 analysis.put()
143 analysis = self.findit.GetAnalysis(crash_identifiers)
144 self.assertIsNotNone(analysis,
145 'FinditForFracas.GetAnalysis unexpectedly returned None')
146
147 self.assertEqual(analysis.crashed_version, crash_data['chrome_version'])
148 self.assertEqual(analysis.signature, crash_data['signature'])
149 self.assertEqual(analysis.platform, crash_data['platform'])
150 self.assertEqual(analysis.stack_trace, crash_data['stack_trace'])
151 channel = crash_data['customized_data'].get('channel', None)
152 self.assertIsNotNone(channel,
153 'channel is unexpectedly not defined in crash_data')
154 self.assertEqual(analysis.channel, channel)
155
156 def testNeedsNewAnalysisIsTrueIfNoAnalysisYet(self):
157 self.assertTrue(self.findit._NeedsNewAnalysis(
158 self.GetDummyCrashData()))
159
160 def testNeedsNewAnalysisIsTrueIfLastOneFailed(self):
161 crash_data = self.GetDummyCrashData()
162 analysis = self.findit.CreateAnalysis(crash_data['crash_identifiers'])
163 analysis.status = analysis_status.ERROR
164 analysis.put()
165 self.assertTrue(self.findit._NeedsNewAnalysis(crash_data))
166
167 def testNeedsNewAnalysisIsFalseIfLastOneIsNotFailed(self):
168 crash_data = self.GetDummyCrashData()
169 crash_identifiers = crash_data['crash_identifiers']
170 for status in (analysis_status.PENDING, analysis_status.RUNNING,
171 analysis_status.COMPLETED, analysis_status.SKIPPED):
172 analysis = self.findit.CreateAnalysis(crash_identifiers)
173 analysis.status = status
174 analysis.put()
175 self.assertFalse(self.findit._NeedsNewAnalysis(crash_data))
176
177 def testFindCulpritForChromeCrashEmptyStacktrace(self):
178 self.mock(chrome_dependency_fetcher.ChromeDependencyFetcher,
179 'GetDependency', lambda *_: {})
180 self.mock(ChromeCrashParser, 'Parse', lambda *_: None)
181
182 analysis = CrashAnalysis()
183 analysis.signature = 'signature'
184 analysis.platform = 'win'
185 analysis.stack_trace = 'frame1\nframe2'
186 analysis.crashed_version = '50.0.1234.0'
187 analysis.historical_metadata = [
188 {'chrome_version': '51.0.1234.0', 'cpm': 0.6}]
189 self.assertIsNone(_FinditForChromeCrash(
190 config=CrashConfig.Get()).FindCulprit(analysis))
191
192 # TODO(http://crbug.com/659346): why do these mocks give coverage
193 # failures? That's almost surely hiding a bug in the tests themselves.
194 def testFindCulpritForChromeCrash(self): # pragma: no cover
195 self.mock(chrome_dependency_fetcher.ChromeDependencyFetcher,
196 'GetDependency', lambda *_: {})
197 stack = CallStack(0)
198 self.mock(ChromeCrashParser, 'Parse',
199 lambda *_: Stacktrace([stack], stack))
200 self.mock(chrome_dependency_fetcher.ChromeDependencyFetcher,
201 'GetDependencyRollsDict',
202 lambda *_: {
203 'src/': DependencyRoll('src/', 'https://repo', '1', '2'),
204 'src/add': DependencyRoll('src/add', 'https://repo1', None, '2'),
205 'src/delete': DependencyRoll('src/delete', 'https://repo2', '2',
206 None)
207 })
208
209 dummy_suspect = Suspect(self.GetDummyChangeLog(), 'src/')
210 self.mock(LogLinearChangelistClassifier, '__call__',
211 lambda _, report: [dummy_suspect] if report.regression_range else [])
212
213 self.mock(ComponentClassifier, 'ClassifySuspects', lambda *_: [])
214 self.mock(ComponentClassifier, 'ClassifyCallStack', lambda *_: [])
215 self.mock(ProjectClassifier, 'ClassifySuspects', lambda *_: '')
216 self.mock(ProjectClassifier, 'ClassifyCallStack', lambda *_: '')
217
218 # TODO(wrengr): for both these tests, we should compare Culprit
219 # objects directly rather than calling ToDicts and comparing the
220 # dictionaries.
221 self._testFindCulpritForChromeCrashSucceeds(dummy_suspect)
222 self._testFindCulpritForChromeCrashFails()
223
224 def _testFindCulpritForChromeCrashSucceeds(self, dummy_suspect):
225 analysis = CrashAnalysis()
226 analysis.signature = 'signature'
227 analysis.platform = 'win'
228 analysis.stack_trace = 'frame1\nframe2'
229 analysis.crashed_version = '50.0.1234.0'
230 dummy_regression_range = ('50.0.1233.0', '50.0.1234.0')
231 analysis.regression_range = dummy_regression_range
232 culprit = _FinditForChromeCrash(config=CrashConfig.Get()).FindCulprit(
233 analysis)
234 self.assertIsNotNone(culprit, 'FindCulprit failed unexpectedly')
235 suspects, tag = culprit.ToDicts()
236
237 expected_suspects = {
238 'found': True,
239 'suspected_cls': [dummy_suspect.ToDict()],
240 'regression_range': dummy_regression_range
241 }
242 expected_tag = {
243 'found_suspects': True,
244 'found_project': False,
245 'found_components': False,
246 'has_regression_range': True,
247 'solution': 'core_algorithm',
248 }
249
250 self.assertDictEqual(expected_suspects, suspects)
251 self.assertDictEqual(expected_tag, tag)
252
253 def _testFindCulpritForChromeCrashFails(self):
254 analysis = CrashAnalysis()
255 analysis.signature = 'signature'
256 analysis.platform = 'win'
257 analysis.stack_trace = 'frame1\nframe2'
258 analysis.crashed_version = '50.0.1234.0'
259 # N.B., analysis.regression_range is None
260 suspects, tag = _FinditForChromeCrash(config=CrashConfig.Get()).FindCulprit(
261 analysis).ToDicts()
262
263 expected_suspects = {'found': False}
264 expected_tag = {
265 'found_suspects': False,
266 'found_project': False,
267 'found_components': False,
268 'has_regression_range': False,
269 'solution': 'core_algorithm',
270 }
271
272 self.assertDictEqual(expected_suspects, suspects)
273 self.assertDictEqual(expected_tag, tag)
274 122
275 @mock.patch('google.appengine.ext.ndb.Key.urlsafe') 123 @mock.patch('google.appengine.ext.ndb.Key.urlsafe')
276 @mock.patch('common.appengine_util.GetDefaultVersionHostname') 124 @mock.patch('common.appengine_util.GetDefaultVersionHostname')
277 def testProcessResultForPublishing(self, mocked_get_default_host, 125 def testProcessResultForPublishing(self, mocked_get_default_host,
278 mocked_urlsafe): 126 mocked_urlsafe):
279 mocked_host = 'http://host' 127 mocked_host = 'http://host'
280 mocked_get_default_host.return_value = mocked_host 128 mocked_get_default_host.return_value = mocked_host
281 urlsafe_key = 'abcde' 129 urlsafe_key = 'abcde'
282 mocked_urlsafe.return_value = urlsafe_key 130 mocked_urlsafe.return_value = urlsafe_key
283 131
284 crash_identifiers = {'signature': 'sig'} 132 crash_identifiers = {'signature': 'sig'}
285 analysis = FracasCrashAnalysis.Create(crash_identifiers) 133 analysis = FracasCrashAnalysis.Create(crash_identifiers)
286 analysis.result = {'other': 'data'} 134 analysis.result = {'other': 'data'}
287 findit_object = _FinditForFracas(config=CrashConfig.Get())
288 expected_processed_suspect = { 135 expected_processed_suspect = {
289 'client_id': findit_object.client_id, 136 'client_id': self._client.client_id,
290 'crash_identifiers': {'signature': 'sig'}, 137 'crash_identifiers': {'signature': 'sig'},
291 'result': { 138 'result': {
292 'feedback_url': ( 139 'feedback_url': (
293 findit_for_chromecrash._FRACAS_FEEDBACK_URL_TEMPLATE % ( 140 findit_for_chromecrash._FRACAS_FEEDBACK_URL_TEMPLATE % (
294 mocked_host, urlsafe_key)), 141 mocked_host, urlsafe_key)),
295 'other': 'data' 142 'other': 'data'
296 } 143 }
297 } 144 }
298 145
299 self.assertDictEqual(findit_object.GetPublishableResult(crash_identifiers, 146 self.assertDictEqual(self._client.GetPublishableResult(crash_identifiers,
300 analysis), 147 analysis),
301 expected_processed_suspect) 148 expected_processed_suspect)
OLDNEW
« no previous file with comments | « appengine/findit/crash/test/crash_report_with_dependencies_test.py ('k') | appengine/findit/crash/test/findit_test.py » ('j') | no next file with comments »

Powered by Google App Engine
This is Rietveld 408576698