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

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

Issue 2414523002: [Findit] Reorganizing findit_for_*.py (Closed)
Patch Set: Addressing the crash_config.fracas issue Created 4 years, 1 month 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 from common import chromium_deps 5 from common import chromium_deps
6 from common.dependency import DependencyRoll 6 from common.dependency import DependencyRoll
7 from crash import detect_regression_range 7 from crash.changelist_classifier import ChangelistClassifier
8 from crash import findit_for_chromecrash 8 from crash.chromecrash_parser import ChromeCrashParser
9 from crash import chromecrash_parser
10 from crash import findit_for_crash
11 from crash.component_classifier import ComponentClassifier 9 from crash.component_classifier import ComponentClassifier
10 from crash.crash_report import CrashReport
11 from crash.culprit import Culprit
12 from crash.culprit import NullCulprit
13 from crash.findit_for_chromecrash import FinditForChromeCrash
14 from crash.findit_for_chromecrash import FinditForFracas
15 from crash.findit import Findit
12 from crash.project_classifier import ProjectClassifier 16 from crash.project_classifier import ProjectClassifier
13 from crash.results import MatchResult 17 from crash.results import MatchResult
14 from crash.stacktrace import CallStack 18 from crash.stacktrace import CallStack
15 from crash.stacktrace import Stacktrace 19 from crash.stacktrace import Stacktrace
20 from crash.type_enums import CrashClient
21 from crash.test.crash_pipeline_test import DummyCrashData
16 from crash.test.crash_testcase import CrashTestCase 22 from crash.test.crash_testcase import CrashTestCase
23 from model import analysis_status
24 from model.crash.crash_analysis import CrashAnalysis
25 from model.crash.fracas_crash_analysis import FracasCrashAnalysis
26
27 # In production we'd use CrashWrapperPipeline. And that'd work fine here,
28 # since we never actually call the method that uses it. But just to be
29 # absolutely sure we don't go over the wire due to some mocking failure,
30 # we'll use this dummy class instead. (In fact, since it's never used,
31 # we don't even need to give a real class; |None| works just fine.)
32 MOCK_PIPELINE_CLS = None
33
34 class _FinditForChromeCrash(FinditForChromeCrash):
35 def __init__(self):
36 super(_FinditForChromeCrash, self).__init__(MOCK_PIPELINE_CLS)
37
38 @classmethod
39 def _ClientID(cls):
40 """Avoid throwing a NotImplementedError.
41
42 Since this method is called from |FinditForChromeCrash.__init__|
43 in order to construct the Azalea object, we need to not throw
44 exceptions since we want to be able to test the FinditForChromeCrash
45 class itself.
46 """
47 return ''
48
49 @property
50 def config(self):
51 """Avoid returning None.
52
53 The default |Findit.config| will return None if the client
54 id is not found in the CrashConfig. This in turn will cause
55 |FinditForChromeCrash.__init__| to crash, since NoneType doesn't
56 have a |get| method. In general it's fine for things to crash, since
57 noone should make instances of Findit subclasses which don't define
58 |_clientID|; but for this test suite, we want to permit instances
59 of FinditForChromeCrash, so that we can test that class directly.
60 """
61 return {}
62
63 def _FinditForFracas():
64 """A helper to pass in the standard pipeline class."""
65 return FinditForFracas(MOCK_PIPELINE_CLS)
17 66
18 67
19 class FinditForChromeCrashTest(CrashTestCase): 68 class FinditForChromeCrashTest(CrashTestCase):
20 69
70 # TODO(wrengr): what was the purpose of this test? As written it's
71 # just testing that mocking works. I'm guessing it was to check that
72 # we fail when the analysis is for the wrong client_id; but if so,
73 # then we shouldn't need to mock FindCulprit...
74 def testFindCulprit(self):
75 self.mock(FinditForChromeCrash, 'FindCulprit',
76 lambda self, *_: NullCulprit())
77
78 # TODO(wrengr): would be less fragile to call
79 # FinditForFracas.CreateAnalysis instead; though if I'm right about
80 # the original purpose of this test, then this is one of the few
81 # places where calling FracasCrashAnalysis directly would actually
82 # make sense.
83 analysis = FracasCrashAnalysis.Create({'signature': 'sig'})
84 # TODO(wrengr): shouldn't FracasCrashAnalysis.Create already have set
85 # the client_id?
86 analysis.client_id = CrashClient.FRACAS
87
88 # TODO(wrengr): just test for the NullCulprit directly; instead of
89 # going through |ToDicts|.
90 result, tags = _FinditForChromeCrash().FindCulprit(analysis).ToDicts()
91 expected_result, expected_tags = NullCulprit().ToDicts()
92 self.assertDictEqual(result, expected_result)
93 self.assertDictEqual(tags, expected_tags)
94
95
96 class FinditForFracasTest(CrashTestCase):
97
98 def testPlatformRename(self):
99 self.assertEqual(_FinditForFracas().RenamePlatform('linux'), 'unix')
100
101 def testCheckPolicyUnsupportedPlatform(self):
102 self.assertIsNone(_FinditForFracas().CheckPolicy(DummyCrashData(
103 platform = 'unsupported_platform')))
104
105 def testCheckPolicyBlacklistedSignature(self):
106 self.assertIsNone(_FinditForFracas().CheckPolicy(DummyCrashData(
107 signature = 'Blacklist marker signature')))
108
109 def testCheckPolicyPlatformRename(self):
110 new_crash_data = _FinditForFracas().CheckPolicy(DummyCrashData(
111 platform = 'linux'))
112 self.assertIsNotNone(new_crash_data,
113 'FinditForFracas.CheckPolicy unexpectedly returned None')
114 self.assertEqual(new_crash_data['platform'], 'unix')
115
116 def testCreateAnalysis(self):
117 self.assertIsNotNone(_FinditForFracas().CreateAnalysis(
118 {'signature': 'sig'}))
119
120 def testGetAnalysis(self):
121 crash_identifiers = {'signature': 'sig'}
122 # TODO(wrengr): would be less fragile to call
123 # FinditForFracas.CreateAnalysis instead.
124 analysis = FracasCrashAnalysis.Create(crash_identifiers)
125 analysis.put()
126 self.assertEqual(_FinditForFracas().GetAnalysis(crash_identifiers),
127 analysis)
128
129 def testInitializeAnalysisForFracas(self):
130 crash_data = DummyCrashData(platform = 'linux')
131 crash_identifiers = crash_data['crash_identifiers']
132
133 findit_client = _FinditForFracas()
134 analysis = findit_client.CreateAnalysis(crash_identifiers)
135 findit_client._InitializeAnalysis(analysis, crash_data)
136 analysis.put()
137 analysis = findit_client.GetAnalysis(crash_identifiers)
138 self.assertIsNotNone(analysis,
139 'FinditForFracas.GetAnalysis unexpectedly returned None')
140
141 self.assertEqual(analysis.crashed_version, crash_data['crashed_version'])
142 self.assertEqual(analysis.signature, crash_data['signature'])
143 self.assertEqual(analysis.platform, crash_data['platform'])
144 self.assertEqual(analysis.stack_trace, crash_data['stack_trace'])
145 channel = crash_data['customized_data'].get('channel', None)
146 self.assertIsNotNone(channel,
147 'channel is unexpectedly not defined in crash_data')
148 self.assertEqual(analysis.channel, channel)
149
150 def testNeedsNewAnalysisIsTrueIfNoAnalysisYet(self):
151 self.assertTrue(_FinditForFracas()._NeedsNewAnalysis(DummyCrashData()))
152
153 def testNeedsNewAnalysisIsTrueIfLastOneFailed(self):
154 findit_client = _FinditForFracas()
155 crash_data = DummyCrashData()
156 analysis = findit_client.CreateAnalysis(crash_data['crash_identifiers'])
157 analysis.status = analysis_status.ERROR
158 analysis.put()
159 self.assertTrue(findit_client._NeedsNewAnalysis(crash_data))
160
161 def testNeedsNewAnalysisIsFalseIfLastOneIsNotFailed(self):
162 findit_client = _FinditForFracas()
163 crash_data = DummyCrashData()
164 crash_identifiers = crash_data['crash_identifiers']
165 for status in (analysis_status.PENDING, analysis_status.RUNNING,
166 analysis_status.COMPLETED, analysis_status.SKIPPED):
167 analysis = findit_client.CreateAnalysis(crash_identifiers)
168 analysis.status = status
169 analysis.put()
170 self.assertFalse(findit_client._NeedsNewAnalysis(crash_data))
171
172 def testScheduleNewAnalysisSkipsUnsupportedChannel(self):
173 self.assertFalse(_FinditForFracas().ScheduleNewAnalysis(DummyCrashData(
174 version = None,
175 signature = None,
176 crash_identifiers = {},
177 channel = 'unsupported_channel')))
178
179 def testScheduleNewAnalysisSkipsUnsupportedPlatform(self):
180 self.assertFalse(_FinditForFracas().ScheduleNewAnalysis(DummyCrashData(
181 version = None,
182 signature = None,
183 platform = 'unsupported_platform',
184 crash_identifiers = {})))
185
186 def testScheduleNewAnalysisSkipsBlackListSignature(self):
187 self.assertFalse(_FinditForFracas().ScheduleNewAnalysis(DummyCrashData(
188 version = None,
189 signature = 'Blacklist marker signature',
190 crash_identifiers = {})))
191
192 def testScheduleNewAnalysisSkipsIfAlreadyCompleted(self):
193 findit_client = _FinditForFracas()
194 crash_data = DummyCrashData()
195 crash_identifiers = crash_data['crash_identifiers']
196 analysis = findit_client.CreateAnalysis(crash_identifiers)
197 analysis.status = analysis_status.COMPLETED
198 analysis.put()
199 self.assertFalse(findit_client.ScheduleNewAnalysis(crash_data))
200
21 def testFindCulpritForChromeCrashEmptyStacktrace(self): 201 def testFindCulpritForChromeCrashEmptyStacktrace(self):
22 def _MockGetChromeDependency(*_): 202 self.mock(chromium_deps, 'GetChromeDependency', lambda *_: {})
23 return {} 203 self.mock(ChromeCrashParser, 'Parse', lambda *_: Stacktrace())
24 204
25 def _MockParse(*_): 205 # TODO(wrengr): use NullCulprit instead
26 return Stacktrace()
27
28 self.mock(chromium_deps, 'GetChromeDependency', _MockGetChromeDependency)
29 self.mock(chromecrash_parser.ChromeCrashParser, 'Parse', _MockParse)
30
31 expected_results = {'found': False} 206 expected_results = {'found': False}
32 expected_tag = {'found_suspects': False, 207 expected_tag = {'found_suspects': False,
33 'has_regression_range': False} 208 'has_regression_range': False}
34 209
35 results, tag = findit_for_chromecrash.FinditForChromeCrash().FindCulprit( 210 analysis = CrashAnalysis()
36 'signature', 'win', 'frame1\nframe2', '50.0.1234.0', 211 analysis.signature = 'signature'
37 [{'chrome_version': '50.0.1234.0', 'cpm': 0.6}]).ToDicts() 212 analysis.platform = 'win'
38 213 analysis.stack_trace = 'frame1\nframe2'
39 self.assertEqual(expected_results, results) 214 analysis.crashed_version = '50.0.1234.0'
40 self.assertEqual(expected_tag, tag) 215 analysis.historical_metadata = [
216 {'chrome_version': '51.0.1234.0', 'cpm': 0.6}]
217 results, tag = _FinditForChromeCrash().FindCulprit(analysis).ToDicts()
218
219 self.assertDictEqual(expected_results, results)
220 self.assertDictEqual(expected_tag, tag)
41 221
42 def testFindCulpritForChromeCrash(self): 222 def testFindCulpritForChromeCrash(self):
43 def _MockGetChromeDependency(*_): 223 self.mock(chromium_deps, 'GetChromeDependency', lambda *_: {})
44 return {} 224 self.mock(ChromeCrashParser, 'Parse', lambda *_: Stacktrace([CallStack(0)]))
45 225 self.mock(chromium_deps, 'GetDEPSRollsDict', lambda *_: {
46 def _MockParse(*_): 226 'src/': DependencyRoll('src/', 'https://repo', '1', '2'),
47 stack = Stacktrace() 227 'src/add': DependencyRoll('src/add', 'https://repo1', None, '2'),
48 stack.append(CallStack(0)) 228 'src/delete': DependencyRoll('src/delete', 'https://repo2', '2', None)
49 return stack 229 })
50
51 def _MockGetDEPSRollsDict(*_):
52 return {'src/': DependencyRoll('src/', 'https://repo', '1', '2'),
53 'src/add': DependencyRoll('src/add', 'https://repo1', None, '2'),
54 'src/delete': DependencyRoll('src/delete', 'https://repo2',
55 '2', None)}
56 230
57 dummy_match_result = MatchResult(self.GetDummyChangeLog(), 'src/') 231 dummy_match_result = MatchResult(self.GetDummyChangeLog(), 'src/')
58 def _MockFindItForCrash(*args): 232 self.mock(ChangelistClassifier, '__call__',
59 regression_deps_rolls = args[1] 233 lambda _self, report:
60 if regression_deps_rolls: 234 [dummy_match_result] if report.regression_range else [])
61 return [dummy_match_result] 235
62 236 self.mock(ComponentClassifier, 'Classify', lambda *_: [])
63 return [] 237 self.mock(ProjectClassifier, 'Classify', lambda *_: '')
64 238
65 def _MockComponentClassify(*_): 239 # TODO(wrengr): for both these tests, we should compare Culprit
66 return [] 240 # objects directly rather than calling ToDicts and comparing the
67 241 # dictionaries.
68 def _MockProjectClassify(*_): 242 self._testFindCulpritForChromeCrashSucceeds(dummy_match_result)
69 return '' 243 self._testFindCulpritForChromeCrashFails()
70 244
71 self.mock(chromium_deps, 'GetChromeDependency', _MockGetChromeDependency) 245 def _testFindCulpritForChromeCrashSucceeds(self, dummy_match_result):
72 self.mock(chromecrash_parser.ChromeCrashParser, 'Parse', _MockParse) 246 analysis = CrashAnalysis()
73 self.mock(chromium_deps, 'GetDEPSRollsDict', _MockGetDEPSRollsDict) 247 analysis.signature = 'signature'
74 self.mock(findit_for_crash, 'FindItForCrash', _MockFindItForCrash) 248 analysis.platform = 'win'
75 249 analysis.stack_trace = 'frame1\nframe2'
76 self.mock(ComponentClassifier, 'Classify', _MockComponentClassify) 250 analysis.crashed_version = '50.0.1234.0'
77 self.mock(ProjectClassifier, 'Classify', _MockProjectClassify) 251 dummy_regression_range = ['50.0.1233.0', '50.0.1234.0']
78 252 analysis.regression_range = dummy_regression_range
79 expected_results = {'found': False} 253 results, tag = _FinditForChromeCrash().FindCulprit(analysis).ToDicts()
80 expected_tag = {'found_suspects': False} 254
81
82 results, tag = findit_for_chromecrash.FinditForChromeCrash().FindCulprit(
83 'signature', 'win', 'frame1\nframe2', '50.0.1234.0',
84 ['50.0.1233.0', '50.0.1234.0']).ToDicts()
85
86 # TODO(wrengr): compare the Culprit object directly to these values,
87 # rather than converting to dicts first. We can make a different
88 # unit test for comparing the dicts, if we actually need/want to.
89 expected_results = { 255 expected_results = {
90 'found': True, 256 'found': True,
91 'suspected_project': '', 257 'suspected_project': '',
92 'suspected_components': [], 258 'suspected_components': [],
93 'suspected_cls': [dummy_match_result.ToDict()], 259 'suspected_cls': [dummy_match_result.ToDict()],
94 'regression_range': ['50.0.1233.0', '50.0.1234.0'] 260 'regression_range': dummy_regression_range
95 } 261 }
96 expected_tag = { 262 expected_tag = {
97 'found_suspects': True, 263 'found_suspects': True,
98 'found_project': False, 264 'found_project': False,
99 'found_components': False, 265 'found_components': False,
100 'has_regression_range': True, 266 'has_regression_range': True,
101 'solution': 'core_algorithm', 267 'solution': 'core_algorithm',
102 } 268 }
103 269
104 self.assertEqual(expected_results, results) 270 self.assertDictEqual(expected_results, results)
105 self.assertEqual(expected_tag, tag) 271 self.assertDictEqual(expected_tag, tag)
106 272
107 results, tag = findit_for_chromecrash.FinditForChromeCrash().FindCulprit( 273 def _testFindCulpritForChromeCrashFails(self):
108 'signature', 'win', 'frame1\nframe2', '50.0.1234.0', None).ToDicts() 274 analysis = CrashAnalysis()
275 analysis.signature = 'signature'
276 analysis.platform = 'win'
277 analysis.stack_trace = 'frame1\nframe2'
278 analysis.crashed_version = '50.0.1234.0'
279 results, tag = _FinditForChromeCrash().FindCulprit(analysis).ToDicts()
109 280
110 expected_results = { 281 expected_results = {
111 'found': False, 282 'found': False,
112 'suspected_project': '', 283 'suspected_project': '',
113 'suspected_components': [], 284 'suspected_components': [],
114 'suspected_cls': [], 285 'suspected_cls': [],
115 'regression_range': None 286 'regression_range': None
116 } 287 }
117 expected_tag = { 288 expected_tag = {
118 'found_suspects': False, 289 'found_suspects': False,
119 'found_project': False, 290 'found_project': False,
120 'found_components': False, 291 'found_components': False,
121 'has_regression_range': False, 292 'has_regression_range': False,
122 'solution': 'core_algorithm', 293 'solution': 'core_algorithm',
123 } 294 }
124 295
125 self.assertEqual(expected_results, results) 296 self.assertDictEqual(expected_results, results)
126 self.assertEqual(expected_tag, tag) 297 self.assertDictEqual(expected_tag, tag)
127
128 def testFieldsProperty(self):
129 culprit = findit_for_chromecrash.Culprit('proj', ['Blink>API'], [],
130 ['50.0.1234.0', '50.0.1234.1'])
131 self.assertEqual(culprit.fields,
132 ('project', 'components', 'cls', 'regression_range'))
OLDNEW

Powered by Google App Engine
This is Rietveld 408576698