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

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

Issue 2657913002: [Predator] Add ``Project`` class and ``ClassifySuspect`` method to project and component classifier (Closed)
Patch Set: Fix nits. 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 from common.pipeline_wrapper import pipeline_handlers 5 from common.pipeline_wrapper import pipeline_handlers
6 from crash.stacktrace import StackFrame 6 from crash.stacktrace import StackFrame
7 from crash.stacktrace import CallStack 7 from crash.stacktrace import CallStack
8 from crash.component_classifier import Component 8 from crash.component_classifier import Component
9 from crash.component_classifier import ComponentClassifier 9 from crash.component_classifier import ComponentClassifier
10 from crash.suspect import Suspect 10 from crash.suspect import Suspect
11 from crash.test.predator_testcase import PredatorTestCase 11 from crash.test.predator_testcase import PredatorTestCase
12 from model.crash.crash_config import CrashConfig 12 from model.crash.crash_config import CrashConfig
13 from libs.gitiles.change_log import ChangeLog 13 from libs.gitiles.change_log import ChangeLog
14 from libs.gitiles.change_log import FileChangeInfo 14 from libs.gitiles.change_log import FileChangeInfo
15 15 from libs.gitiles.diff import ChangeType
16
17 # N.B., the call to Get() in CrashConfigComponentClassifier.__init__
18 # must only be executed from within the testFoo methods of
19 # ComponentClassifierTest. That is, we can't just do this once and for all
20 # when doing ComponentClassifierTest.__init__, because that'll cause some
21 # strange issues in mocking. But factoring it out like this so it gets
22 # (re)called ever time a testFoo is run, that works.
23 class CrashConfigComponentClassifier(ComponentClassifier):
24 """A ComponentClassifier which gets its components from CrashConfig."""
25 def __init__(self):
26 config = CrashConfig.Get().component_classifier
27 super(CrashConfigComponentClassifier, self).__init__(
28 [Component(name, path, function)
29 for path, function, name
30 in config.get('path_function_component', [])],
31 config.get('top_n', 0))
32 16
33 17
34 class ComponentClassifierTest(PredatorTestCase): 18 class ComponentClassifierTest(PredatorTestCase):
19 """Tests ``ComponentClassifier`` class."""
35 20
36 def setUp(self): 21 def setUp(self):
37 super(ComponentClassifierTest, self).setUp() 22 super(ComponentClassifierTest, self).setUp()
38 # Only construct the cccc once, rather than making a new one every 23 config = CrashConfig.Get().component_classifier
24 components = [Component(component_name, path_regex, function_regex)
25 for path_regex, function_regex, component_name
26 in config['path_function_component']]
27 # Only construct the classifier once, rather than making a new one every
39 # time we call a method on it. 28 # time we call a method on it.
40 self.cccc = CrashConfigComponentClassifier() 29 self.classifier = ComponentClassifier(components, config['top_n'])
41 30
42 def testGetClassFromStackFrame(self): 31 def testClassifyCallStack(self):
43 frame = StackFrame(0, 'src/', 'func', 'comp1.cc', 'src/comp1.cc', [2]) 32 """Tests ``ClassifyCallStack`` method."""
44 self.assertEqual(self.cccc.GetClassFromStackFrame(frame), 'Comp1>Dummy') 33 callstack = CallStack(
45 34 0, [StackFrame(0, 'src/', 'func', 'comp1.cc', 'src/comp1.cc', [2])])
46 frame = StackFrame(0, 'src/', 'func2', 'comp2.cc', 'src/comp2.cc', [32]) 35 self.assertEqual(self.classifier.ClassifyCallStack(callstack),
47 self.assertEqual(self.cccc.GetClassFromStackFrame(frame), 'Comp2>Dummy')
48
49 frame = StackFrame(0, 'src/', 'no_func', 'comp2.cc', 'src/comp2.cc', [32])
50 self.assertEqual(self.cccc.GetClassFromStackFrame(frame), '')
51
52 frame = StackFrame(0, 'src/', 'func2', 'a.cc', 'src/a.cc', [6])
53 self.assertEqual(self.cccc.GetClassFromStackFrame(frame), '')
54
55 def testGetClassFromSuspect(self):
56 suspect = Suspect(self.GetDummyChangeLog(), 'src/')
57 self.assertEqual(self.cccc.GetClassFromSuspect(suspect), '')
58
59 suspect.file_to_stack_infos = {
60 'comp1.cc': [
61 (StackFrame(0, 'src/', 'func', 'comp1.cc', 'src/comp1.cc', [2]), 0)
62 ]
63 }
64 self.assertEqual(self.cccc.GetClassFromSuspect(suspect), 'Comp1>Dummy')
65
66 def testClassifyCrashStack(self):
67 crash_stack = CallStack(0, frame_list=[
68 StackFrame(0, 'src/', 'func', 'comp1.cc', 'src/comp1.cc', [2]),
69 StackFrame(1, 'src/', 'ff', 'comp1.cc', 'src/comp1.cc', [21]),
70 StackFrame(2, 'src/', 'func2', 'comp2.cc', 'src/comp2.cc', [8])])
71
72 self.assertEqual(self.cccc.Classify([], crash_stack),
73 ['Comp1>Dummy', 'Comp2>Dummy'])
74
75 def testClassifySuspects(self):
76 suspect = Suspect(self.GetDummyChangeLog(), 'src/')
77 suspect.file_to_stack_infos = {
78 'comp1.cc': [
79 (StackFrame(0, 'src/', 'func', 'comp1.cc', 'src/comp1.cc', [2]), 0)
80 ]
81 }
82
83 self.assertEqual(self.cccc.Classify([suspect], CallStack(0)),
84 ['Comp1>Dummy']) 36 ['Comp1>Dummy'])
85 37
86 def testClassifierDoNotHaveConfig(self): 38 callstack = CallStack(
87 crash_config = CrashConfig.Get() 39 0, [StackFrame(0, 'dummy/', 'no_func', 'comp2.cc',
88 crash_config.component_classifier = {} 40 'dummy/comp2.cc', [32])])
89 # N.B., we must construct a new cccc here, becasue we changed CrashConfig. 41 self.assertEqual(self.classifier.ClassifyCallStack(callstack), [])
90 self.cccc = CrashConfigComponentClassifier()
91 42
92 crash_stack = CallStack(0, frame_list=[ 43 crash_stack = CallStack(0, frame_list=[
93 StackFrame(0, 'src/', 'func', 'comp1.cc', 'src/comp1.cc', [2]), 44 StackFrame(0, 'src/', 'func', 'comp1.cc', 'src/comp1.cc', [2]),
94 StackFrame(1, 'src/', 'ff', 'comp1.cc', 'src/comp1.cc', [21]), 45 StackFrame(1, 'src/', 'ff', 'comp1.cc', 'src/comp1.cc', [21]),
95 StackFrame(2, 'src/', 'func2', 'comp2.cc', 'src/comp2.cc', [8])]) 46 StackFrame(2, 'src/', 'func2', 'comp2.cc', 'src/comp2.cc', [8])])
96 47
48 self.assertEqual(self.classifier.ClassifyCallStack(crash_stack),
49 ['Comp1>Dummy', 'Comp2>Dummy'])
50
51 def testClassifySuspect(self):
52 """Tests ``ClassifySuspect`` method."""
97 suspect = Suspect(self.GetDummyChangeLog(), 'src/') 53 suspect = Suspect(self.GetDummyChangeLog(), 'src/')
98 suspect.file_to_stack_infos = { 54 suspect.changelog = suspect.changelog._replace(
99 'comp1.cc': [ 55 touched_files = [FileChangeInfo(ChangeType.MODIFY,
100 (StackFrame(0, 'src/', 'func', 'comp1.cc', 'src/comp1.cc', [2]), 0) 56 'comp1.cc', 'comp1.cc')])
101 ] 57 self.assertEqual(self.classifier.ClassifySuspect(suspect), ['Comp1>Dummy'])
102 }
103 58
104 self.assertEqual(self.cccc.Classify([suspect], crash_stack), []) 59 def testClassifyEmptySuspect(self):
60 """Tests ``ClassifySuspect`` returns None for empty suspect."""
61 self.assertIsNone(self.classifier.ClassifySuspect(None))
105 62
106 def testGetClassFromFileChangeInfo(self): 63 def testClassifySuspectNoMatch(self):
107 self.assertEqual( 64 """Tests ``ClassifySuspect`` returns None if there is no file match."""
108 CrashConfigComponentClassifier().GetClassFromFileChangeInfo( 65 suspect = Suspect(self.GetDummyChangeLog(), 'dummy')
109 FileChangeInfo.FromDict({'change_type': 'modify', 66 suspect.changelog = suspect.changelog._replace(
110 'old_path': 'src/comp1.cc', 67 touched_files = [FileChangeInfo(ChangeType.MODIFY,
111 'new_path': 'src/comp1.cc'})), 68 'comp1.cc', 'comp1.cc')])
112 'Comp1>Dummy') 69 self.assertEqual(self.classifier.ClassifySuspect(suspect), [])
113 70
114 def testGetClassFromFileChangeInfoOldPath(self): 71 def testClassifySuspects(self):
115 self.assertEqual( 72 """Tests ``ClassifySuspects`` classify a list of ``Suspect``s."""
116 CrashConfigComponentClassifier().GetClassFromFileChangeInfo( 73 suspect1 = Suspect(self.GetDummyChangeLog(), 'src/')
117 FileChangeInfo.FromDict({'change_type': 'delete', 74 suspect1.changelog = suspect1.changelog._replace(
118 'old_path': 'src/comp1.cc', 75 touched_files = [FileChangeInfo(ChangeType.MODIFY,
119 'new_path': ''})), 76 'comp1.cc', 'comp1.cc')])
120 'Comp1>Dummy') 77 suspect2 = Suspect(self.GetDummyChangeLog(), 'src/')
78 suspect2.changelog = suspect2.changelog._replace(
79 touched_files = [FileChangeInfo(ChangeType.MODIFY,
80 'comp2.cc', 'comp2.cc')])
121 81
122 82 self.assertEqual(self.classifier.ClassifySuspects([suspect1, suspect2]),
123 def testGetClassFromNoneFileChangeInfo(self): 83 ['Comp1>Dummy', 'Comp2>Dummy'])
124 self.assertEqual(
125 CrashConfigComponentClassifier().GetClassFromFileChangeInfo(None),
126 None)
127
128 def testGetClassFromChangeFileInfoNoMapping(self):
129 self.assertEqual(
130 CrashConfigComponentClassifier().GetClassFromFileChangeInfo(
131 FileChangeInfo.FromDict({'change_type':'modify',
132 'old_path':'file',
133 'new_path':'file'})),'')
134
135 def testGetClassFromChangeFileInfoNoMappingOldPath(self):
136 self.assertEqual(
137 CrashConfigComponentClassifier().GetClassFromFileChangeInfo(
138 FileChangeInfo.FromDict({'change_type':'rename',
139 'old_path':'old_file',
140 'new_path':'new_file'})),'')
141
142 def testClassifyChangeLog(self):
143 change_log = ChangeLog.FromDict({
144 'author': {
145 'name': 'a',
146 'email': 'b@email.com',
147 'time': '2014-08-13 00:53:12',
148 },
149 'committer': {
150 'name': 'c',
151 'email': 'd@email.com',
152 'time': '2014-08-14 00:53:12',
153 },
154 'revision': 'aaaa',
155 'commit_position': 1111,
156 'touched_files': [
157 {
158 'change_type': 'copy',
159 'old_path': 'file',
160 'new_path': 'src/comp2.cc'
161 },
162 {
163 'change_type': 'modify',
164 'old_path': 'src/comp2.cc',
165 'new_path': 'src/comp2.cc'
166 },
167 {
168 'change_type': 'modify',
169 'old_path': 'src/comp1.cc',
170 'new_path': 'src/comp1.cc'
171 }
172 ],
173 'message': 'blabla...',
174 'commit_url':
175 'https://chromium.googlesource.com/chromium/src/+/git_hash',
176 'code_review_url': 'https://codereview.chromium.org/2222',
177 'reverted_revision': '8d4a4fa6s18raf3re12tg6r'})
178 self.assertEqual(
179 CrashConfigComponentClassifier().ClassifyChangeLog(change_log),
180 ['Comp2>Dummy', 'Comp1>Dummy'])
181
182 def testClassifyNoneChangeLog(self):
183 change_log = None
184 self.assertEqual(
185 CrashConfigComponentClassifier().ClassifyChangeLog(change_log),
186 None)
187
188 def testClassifyChangeLogNoMapping(self):
189 change_log = ChangeLog.FromDict({
190 'author': {
191 'name': 'a',
192 'email': 'b@email.com',
193 'time': '2014-08-13 00:53:12',
194 },
195 'committer': {
196 'name': 'c',
197 'email': 'd@email.com',
198 'time': '2014-08-14 00:53:12',
199 },
200 'revision': 'aaaa',
201 'commit_position': 1111,
202 'touched_files': [
203 {
204 'change_type': 'rename',
205 'old_path': 'old_file',
206 'new_path': 'new_file'
207 },
208 {
209 'change_type': 'delete',
210 'old_path': 'file',
211 'new_path': 'file'
212 }
213 ],
214 'message': 'blabla...',
215 'commit_url':
216 'https://chromium.googlesource.com/chromium/src/+/git_hash',
217 'code_review_url': 'https://codereview.chromium.org/2222',
218 'reverted_revision': '8d4a4fa6s18raf3re12tg6r'})
219 self.assertEqual(
220 CrashConfigComponentClassifier().ClassifyChangeLog(change_log),
221 [])
OLDNEW
« no previous file with comments | « appengine/findit/crash/project_classifier.py ('k') | appengine/findit/crash/test/findit_for_chromecrash_test.py » ('j') | no next file with comments »

Powered by Google App Engine
This is Rietveld 408576698