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

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

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

Powered by Google App Engine
This is Rietveld 408576698