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

Side by Side Diff: appengine/findit/crash/loglinear/test/changelist_classifier_test.py

Issue 2707603002: [Predator] Generate all changelogs in regression ranges instead of only matched changelogs (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 logging 6 import logging
7 import math 7 import math
8 import pprint
9 8
10 from common.dependency import Dependency 9 from common.dependency import Dependency
11 from common.dependency import DependencyRoll 10 from common.dependency import DependencyRoll
12 from common.chrome_dependency_fetcher import ChromeDependencyFetcher
13 import crash.changelist_classifier as scorer_changelist_classifier
14 from crash.crash_report import CrashReport 11 from crash.crash_report import CrashReport
15 from crash.loglinear.changelist_classifier import LogLinearChangelistClassifier 12 from crash.loglinear.changelist_classifier import LogLinearChangelistClassifier
16 from crash.loglinear.changelist_features.touch_crashed_file_meta import ( 13 from crash.loglinear.changelist_features.touch_crashed_file_meta import (
17 TouchCrashedFileMetaFeature) 14 TouchCrashedFileMetaFeature)
15 from crash.loglinear.feature import MetaFeatureValue
18 from crash.loglinear.feature import WrapperMetaFeature 16 from crash.loglinear.feature import WrapperMetaFeature
19 from crash.loglinear.weight import Weight 17 from crash.loglinear.weight import Weight
20 from crash.loglinear.weight import MetaWeight 18 from crash.loglinear.weight import MetaWeight
21 from crash.suspect import AnalysisInfo
22 from crash.suspect import Suspect 19 from crash.suspect import Suspect
23 from crash.suspect import StackInfo
24 from crash.stacktrace import CallStack 20 from crash.stacktrace import CallStack
25 from crash.stacktrace import StackFrame 21 from crash.stacktrace import StackFrame
26 from crash.stacktrace import Stacktrace 22 from crash.stacktrace import Stacktrace
27 from crash.test.crash_test_suite import CrashTestSuite 23 from crash.test.crash_test_suite import CrashTestSuite
28 from crash.type_enums import CallStackFormatType 24 from crash.type_enums import CallStackFormatType
29 from crash.type_enums import LanguageType 25 from crash.type_enums import LanguageType
30 from libs.gitiles.blame import Blame
31 from libs.gitiles.blame import Region
32 from libs.gitiles.change_log import ChangeLog 26 from libs.gitiles.change_log import ChangeLog
33 from libs.gitiles.gitiles_repository import GitilesRepository 27 from libs.gitiles.gitiles_repository import GitilesRepository
28 import libs.math.logarithms as lmath
34 29
35 DUMMY_CHANGELOG1 = ChangeLog.FromDict({ 30 DUMMY_CHANGELOG1 = ChangeLog.FromDict({
36 'author': { 31 'author': {
37 'name': 'r@chromium.org', 32 'name': 'r@chromium.org',
38 'email': 'r@chromium.org', 33 'email': 'r@chromium.org',
39 'time': 'Thu Mar 31 21:24:43 2016', 34 'time': 'Thu Mar 31 21:24:43 2016',
40 }, 35 },
41 'committer': { 36 'committer': {
42 'email': 'r@chromium.org', 37 'email': 'r@chromium.org',
43 'time': 'Thu Mar 31 21:28:39 2016', 38 'time': 'Thu Mar 31 21:28:39 2016',
(...skipping 73 matching lines...) Expand 10 before | Expand all | Expand 10 after
117 112
118 DUMMY_CALLSTACKS = [ 113 DUMMY_CALLSTACKS = [
119 CallStack(0, [], CallStackFormatType.DEFAULT, LanguageType.CPP), 114 CallStack(0, [], CallStackFormatType.DEFAULT, LanguageType.CPP),
120 CallStack(1, [], CallStackFormatType.DEFAULT, LanguageType.CPP)] 115 CallStack(1, [], CallStackFormatType.DEFAULT, LanguageType.CPP)]
121 DUMMY_REPORT = CrashReport( 116 DUMMY_REPORT = CrashReport(
122 None, None, None, Stacktrace(DUMMY_CALLSTACKS, DUMMY_CALLSTACKS[0]), 117 None, None, None, Stacktrace(DUMMY_CALLSTACKS, DUMMY_CALLSTACKS[0]),
123 (None, None), None, None) 118 (None, None), None, None)
124 119
125 120
126 class LogLinearChangelistClassifierTest(CrashTestSuite): 121 class LogLinearChangelistClassifierTest(CrashTestSuite):
122 """Tests ``LogLinearChangelistClassifier`` class."""
127 123
128 def setUp(self): 124 def setUp(self):
129 super(LogLinearChangelistClassifierTest, self).setUp() 125 super(LogLinearChangelistClassifierTest, self).setUp()
130 meta_weight = MetaWeight({ 126 meta_weight = MetaWeight({
131 'TouchCrashedFileMeta': MetaWeight({ 127 'TouchCrashedFileMeta': MetaWeight({
132 'MinDistance': Weight(1.), 128 'MinDistance': Weight(1.),
133 'TopFrameIndex': Weight(1.), 129 'TopFrameIndex': Weight(1.),
134 'TouchCrashedFile': Weight(1.), 130 'TouchCrashedFile': Weight(1.),
135 }) 131 })
136 }) 132 })
137 get_repository = GitilesRepository.Factory(self.GetMockHttpClient()) 133 get_repository = GitilesRepository.Factory(self.GetMockHttpClient())
138 meta_feature = WrapperMetaFeature( 134 meta_feature = WrapperMetaFeature(
139 [TouchCrashedFileMetaFeature(get_repository)]) 135 [TouchCrashedFileMetaFeature(get_repository)])
140 136
141 self.changelist_classifier = LogLinearChangelistClassifier( 137 self.changelist_classifier = LogLinearChangelistClassifier(
142 get_repository, meta_feature, meta_weight) 138 get_repository, meta_feature, meta_weight)
143 139
144 # TODO(http://crbug.com/659346): why do these mocks give coverage 140 def testCallFailedFindingSuspects(self):
145 # failures? That's almost surely hiding a bug in the tests themselves. 141 """Tests that ``__call__`` method failed to find suspects."""
146 def testFindItForCrashNoRegressionRange(self): # pragma: no cover 142 self.mock(self.changelist_classifier, 'GenerateSuspects', lambda *_: [])
147 # N.B., for this one test we really do want regression_range=None. 143 suspects = self.changelist_classifier(DUMMY_REPORT)
148 report = CrashReport(None, None, None, Stacktrace(DUMMY_CALLSTACKS, 144 self.assertListEqual(suspects, [])
149 DUMMY_CALLSTACKS[0]),
150 None, {}, {})
151 self.assertListEqual(self.changelist_classifier(report), [])
152 145
153 def testFindItForCrashNoMatchFound(self): 146 def testCallFindsSuspects(self):
154 self.mock(scorer_changelist_classifier, 'FindSuspects', lambda *_: []) 147 """Tests that ``__call__`` method finds suspects."""
155 self.assertListEqual(self.changelist_classifier(DUMMY_REPORT), []) 148 suspect1 = Suspect(DUMMY_CHANGELOG1, 'src/')
149 suspect2 = Suspect(DUMMY_CHANGELOG2, 'src/')
156 150
157 self.mock(scorer_changelist_classifier, 'FindSuspects', lambda *_: None) 151 self.mock(self.changelist_classifier, 'GenerateSuspects',
158 self.assertListEqual(self.changelist_classifier(DUMMY_REPORT), []) 152 lambda *_: [suspect1, suspect2])
153 self.mock(self.changelist_classifier, 'RankSuspects',
154 lambda report, suspects: [suspects[0]])
155 suspects = self.changelist_classifier(DUMMY_REPORT)
159 156
160 def testFindItForCrash(self): 157 expected_suspects = [suspect1.ToDict()]
161 suspect1 = Suspect(DUMMY_CHANGELOG1, 'src/')
162 suspect2 = Suspect(DUMMY_CHANGELOG3, 'src/')
163
164 a_cc_blame = Blame('6', 'src/')
165 a_cc_blame.AddRegions([Region(0, 10, suspect1.changelog.revision,
166 suspect1.changelog.author.name,
167 suspect1.changelog.author.email,
168 suspect1.changelog.author.time)])
169 f_cc_blame = Blame('6', 'src/')
170 f_cc_blame.AddRegions([Region(21, 10, suspect2.changelog.revision,
171 suspect2.changelog.author.name,
172 suspect2.changelog.author.email,
173 suspect2.changelog.author.time)])
174 url_to_blame = {'6/a.cc': a_cc_blame,
175 '6/f.cc': f_cc_blame}
176
177 def _MockGetBlame(_, path, revision):
178 revision_path = '%s/%s' % (revision, path)
179 return url_to_blame.get(revision_path)
180
181 self.mock(GitilesRepository, 'GetBlame', _MockGetBlame)
182 self.mock(scorer_changelist_classifier,
183 'GetChangeLogsForFilesGroupedByDeps',
184 lambda *_: (None, None))
185 self.mock(scorer_changelist_classifier, 'FindSuspects',
186 lambda *_: [suspect1, suspect2])
187 frame1 = StackFrame(0, 'src/', 'func', 'a.cc', 'src/a.cc', [1])
188 frame2 = StackFrame(1, 'src/', 'func', 'a.cc', 'src/a.cc', [7])
189 frame3 = StackFrame(15, 'src/', 'func', 'f.cc', 'src/f.cc', [1])
190 frame4 = StackFrame(3, 'src/dep1', 'func', 'f.cc', 'src/dep1/f.cc', [1])
191 stacks = [CallStack(0, frame_list=[frame1, frame2, frame3, frame4])]
192 stacktrace = Stacktrace(stacks, stacks[0])
193 report = CrashReport(
194 '6', 'sig', 'win', stacktrace, ('0', '4'),
195 {'src/': Dependency('src/', 'https://repo', '6')},
196 {'src/': DependencyRoll('src/', 'https://repo', '0', '4')} )
197
198 suspects = self.changelist_classifier(report)
199 self.assertTrue(suspects,
200 'Expected suspects, but the classifier didn\'t return any')
201
202 expected_suspects = [
203 {
204 'author': 'r@chromium.org',
205 'changed_files': [
206 {
207 'blame_url': None,
208 'file': 'a.cc',
209 'info': ('Distance from touched lines and crashed lines is '
210 '0, in frame #0')
211 }
212 ],
213 'confidence': 0.,
214 'project_path': 'src/',
215 'reasons': ('MinDistance: 0.000000 -- Minimum distance is '
216 '0\nTopFrameIndex: 0.000000 -- Top frame is #0\n'
217 'TouchCrashedFile: 0.000000 -- Touched files - a.cc'),
218 'review_url': 'https://codereview.chromium.org/3281',
219 'revision': '1',
220 'time': 'Thu Mar 31 21:24:43 2016',
221 'url': 'https://repo.test/+/1'
222 },
223 ]
224 self.assertListEqual([suspect.ToDict() for suspect in suspects], 158 self.assertListEqual([suspect.ToDict() for suspect in suspects],
225 expected_suspects) 159 expected_suspects)
160
161 def testGenerateSuspects(self):
162 """Tests ``GenerateSuspects`` method."""
163 dep_roll = DependencyRoll('src/', 'https://repo', 'rev1', 'rev5')
164 report = DUMMY_REPORT._replace(dependency_rolls={dep_roll.path: dep_roll})
165 self.mock(GitilesRepository, 'GetChangeLogs',
166 lambda *_: [DUMMY_CHANGELOG1, DUMMY_CHANGELOG2, DUMMY_CHANGELOG3])
167
168 suspects = self.changelist_classifier.GenerateSuspects(report)
169 self.assertListEqual([Suspect(DUMMY_CHANGELOG3, 'src/').ToDict()],
170 [suspect.ToDict() for suspect in suspects])
171
172 def testRankSuspectsAllLogZeros(self):
173 """Tests ``RankSuspects`` method."""
174 self.mock(self.changelist_classifier._model, 'Features',
175 lambda _: lambda _: MetaFeatureValue('dummy', {}))
176 suspect1 = Suspect(DUMMY_CHANGELOG1, 'src/')
177 suspect2 = Suspect(DUMMY_CHANGELOG2, 'src/')
178
179 self.mock(self.changelist_classifier._model, 'Score',
180 lambda _: lambda _: lmath.LOG_ZERO)
181 suspects = self.changelist_classifier.RankSuspects(DUMMY_REPORT,
182 [suspect1, suspect2])
183 self.assertEqual(suspects, [])
184
185 def testRankSuspects(self):
186 """Tests ``RankSuspects`` method."""
187 self.mock(self.changelist_classifier._model, 'Features',
188 lambda _: lambda _: MetaFeatureValue('dummy', {}))
189
190 suspect = Suspect(DUMMY_CHANGELOG1, 'src/')
191 self.mock(self.changelist_classifier._model, 'Score',
192 lambda _: lambda _: lmath.LOG_ONE)
193 suspects = self.changelist_classifier.RankSuspects(DUMMY_REPORT,
194 [suspect])
195 self.assertEqual(suspects[0].ToDict(), suspect.ToDict())
OLDNEW

Powered by Google App Engine
This is Rietveld 408576698