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

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

Issue 1861373003: [Findit] Initial code of findit for crash. Add scorers to apply heuristic rules. (Closed) Base URL: https://chromium.googlesource.com/infra/infra.git@master
Patch Set: Fix nits and rebase Created 4 years, 8 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
(Empty)
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
3 # found in the LICENSE file.
4
5 from collections import defaultdict
6
7 from common.blame import Region, Blame
8 from common.change_log import ChangeLog
9 from common.dependency import Dependency, DependencyRoll
10 from common.git_repository import GitRepository
11 from crash import findit_for_crash
12 from crash.callstack import StackFrame, CallStack
13 from crash.results import MatchResult
14 from crash.stacktrace import Stacktrace
15 from crash.test.crash_test_suite import CrashTestSuite
16
17
18 DUMMY_CHANGELOG1 = ChangeLog.FromDict({
19 'author_name': 'r@chromium.org',
20 'message': 'dummy',
21 'committer_email': 'r@chromium.org',
22 'commit_position': 175900,
23 'author_email': 'r@chromium.org',
24 'touched_files': [
25 {
26 'change_type': 'add',
27 'new_path': 'a.cc',
28 'old_path': None,
29 },
30 ],
31 'author_time': 'Thu Mar 31 21:24:43 2016',
32 'committer_time': 'Thu Mar 31 21:28:39 2016',
33 'commit_url':
34 'https://repo.test/+/1',
35 'code_review_url': 'https://codereview.chromium.org/3281',
36 'committer_name': 'example@chromium.org',
37 'revision': '1',
38 'reverted_revision': None
39 })
40
41 DUMMY_CHANGELOG2 = ChangeLog.FromDict({
42 'author_name': 'example@chromium.org',
43 'message': 'dummy',
44 'committer_email': 'example@chromium.org',
45 'commit_position': 175976,
46 'author_email': 'example@chromium.org',
47 'touched_files': [
48 {
49 'change_type': 'add',
50 'new_path': 'f0.cc',
51 'old_path': 'b/f0.cc'
52 },
53 ],
54 'author_time': 'Thu Mar 31 21:24:43 2016',
55 'committer_time': 'Thu Mar 31 21:28:39 2016',
56 'commit_url':
57 'https://repo.test/+/2',
58 'code_review_url': 'https://codereview.chromium.org/3281',
59 'committer_name': 'example@chromium.org',
60 'revision': '2',
61 'reverted_revision': '1'
62 })
63
64 DUMMY_CHANGELOG3 = ChangeLog.FromDict({
65 'author_name': 'e@chromium.org',
66 'message': 'dummy',
67 'committer_email': 'e@chromium.org',
68 'commit_position': 176000,
69 'author_email': 'e@chromium.org',
70 'touched_files': [
71 {
72 'change_type': 'modify',
73 'new_path': 'f.cc',
74 'old_path': 'f.cc'
75 },
76 {
77 'change_type': 'delete',
78 'new_path': None,
79 'old_path': 'f1.cc'
80 },
81 ],
82 'author_time': 'Thu Apr 1 21:24:43 2016',
83 'committer_time': 'Thu Apr 1 21:28:39 2016',
84 'commit_url':
85 'https://repo.test/+/3',
86 'code_review_url': 'https://codereview.chromium.org/3281',
87 'committer_name': 'example@chromium.org',
88 'revision': '3',
89 'reverted_revision': None
90 })
91
92
93 class FinditForCrashTest(CrashTestSuite):
94
95 def testGetDepsInCrashStack(self):
96 crash_stack = CallStack(0)
97 crash_stack.extend([
98 StackFrame(0, 'src/', '', 'func0', 'f0.cc', [1]),
99 StackFrame(1, 'src/', '', 'func1', 'f1.cc', [2, 3]),
100 ])
101 crash_deps = {'src/': Dependency('src/', 'https://chromium_repo', '1'),
102 'src/v8/': Dependency('src/v8/', 'https://v8_repo', '2')}
103
104 expected_stack_deps = {'src/': crash_deps['src/']}
105
106 self.assertEqual(
107 findit_for_crash.GetDepsInCrashStack(crash_stack, crash_deps),
108 expected_stack_deps)
109
110 def testGetChangeLogsForFilesGroupedByDeps(self):
111 regression_deps_rolls = {
112 'src/dep1': {
113 'path': 'src/dep1',
114 'repo_url': 'https://url_dep1',
115 'old_revision': '7',
116 'new_revision': '9',
117 },
118 'src/dep2': {
119 'path': 'src/dep2',
120 'repo_url': 'https://url_dep2',
121 'old_revision': '3',
122 'new_revision': None,
123 },
124 'src/': {
125 'path': 'src/',
126 'repo_url': ('https://chromium.googlesource.com/chromium/'
127 'src.git'),
128 'old_revision': '4',
129 'new_revision': '5',
130 },
131 }
132
133 stack_deps = {
134 'src/': Dependency('src/', 'https://url_src', 'rev1', 'DEPS'),
135 }
136
137 def _MockGetChangeLogs(*_):
138 return [DUMMY_CHANGELOG1, DUMMY_CHANGELOG2, DUMMY_CHANGELOG3]
139
140 self.mock(GitRepository, 'GetChangeLogs', _MockGetChangeLogs)
141
142 dep_file_to_changelogs, ignore_cls = (
143 findit_for_crash.GetChangeLogsForFilesGroupedByDeps(
144 regression_deps_rolls, stack_deps))
145 dep_file_to_changelogs_json = defaultdict(lambda: defaultdict(list))
146 for dep, file_to_changelogs in dep_file_to_changelogs.iteritems():
147 for file_path, changelogs in file_to_changelogs.iteritems():
148 for changelog in changelogs:
149 dep_file_to_changelogs_json[dep][file_path].append(changelog.ToDict())
150
151 expected_dep_file_to_changelogs_json = {
152 'src/': {
153 'a.cc': [DUMMY_CHANGELOG1.ToDict()],
154 'f.cc': [DUMMY_CHANGELOG3.ToDict()]
155 }
156 }
157 self.assertEqual(dep_file_to_changelogs_json,
158 expected_dep_file_to_changelogs_json)
159 self.assertEqual(ignore_cls, set(['1']))
160
161 def testGetStackInfosForFilesGroupedByDeps(self):
162
163 main_stack = CallStack(0)
164 main_stack.extend(
165 [StackFrame(0, 'src/', '', 'c(p* &d)', 'a.cc', [177]),
166 StackFrame(1, 'src/', '', 'd(a* c)', 'a.cc', [227, 228, 229]),
167 StackFrame(2, 'src/v8/', '', 'e(int)', 'b.cc', [87, 88, 89, 90])])
168
169 low_priority_stack = CallStack(1)
170 low_priority_stack.append(
171 StackFrame(0, 'src/dummy/', '', 'c(p* &d)', 'd.cc', [17]))
172
173 stacktrace = Stacktrace()
174 stacktrace.extend([main_stack, low_priority_stack])
175
176 crashed_deps = {'src/': Dependency('src/', 'https//repo', '2'),
177 'src/v8/': Dependency('src/v8', 'https//repo', '1')}
178
179 expected_dep_file_to_stack_infos = {
180 'src/': {
181 'a.cc': [
182 (main_stack[0], 0),
183 (main_stack[1], 0),
184 ],
185 },
186 'src/v8/': {
187 'b.cc': [
188 (main_stack[2], 0),
189 ]
190 }
191 }
192
193 dep_file_to_stack_infos = (
194 findit_for_crash.GetStackInfosForFilesGroupedByDeps(
195 stacktrace, crashed_deps))
196
197 self.assertEqual(len(dep_file_to_stack_infos),
198 len(expected_dep_file_to_stack_infos))
199
200 for dep, file_to_stack_infos in dep_file_to_stack_infos.iteritems():
201 self.assertTrue(dep in expected_dep_file_to_stack_infos)
202 expected_file_to_stack_infos = expected_dep_file_to_stack_infos[dep]
203
204 for file_path, stack_infos in file_to_stack_infos.iteritems():
205 self.assertTrue(file_path in expected_file_to_stack_infos)
206 expected_stack_infos = expected_file_to_stack_infos[file_path]
207
208 self._VerifyTwoStackInfosEqual(stack_infos, expected_stack_infos)
209
210 def testGetBlameForFilesGroupedByDeps(self):
211
212 dummy_blame = Blame('1', 'a.cc')
213 dummy_blame.AddRegion(
214 Region(1, 5, '0', 'a', 'a@email.com', 'Thu Mar 25 21:24:43 2016'))
215 dummy_blame.AddRegion(
216 Region(6, 10, '1', 'b', 'b@email.com', 'Thu Mar 31 21:24:43 2016'))
217
218 def _MockGetBlame(*_):
219 return dummy_blame
220
221 self.mock(GitRepository, 'GetBlame', _MockGetBlame)
222
223 main_stack = CallStack(0)
224 main_stack.extend(
225 [StackFrame(0, 'src/', '', 'c(p* &d)', 'a.cc', [177]),
226 StackFrame(1, 'src/', '', 'd(a* c)', 'a.cc', [227, 228, 229])])
227
228 low_priority_stack = CallStack(1)
229 low_priority_stack.append(
230 StackFrame(0, 'dummy_dep/', '', 'k(p* &d)', 'h.cc', [17]))
231
232 stacktrace = Stacktrace()
233 stacktrace.extend([main_stack, low_priority_stack])
234
235 crash_deps = {'src/': Dependency('src/', 'https://chromium_repo', '1')}
236
237 dep_file_to_blame = findit_for_crash.GetBlameForFilesGroupedByDeps(
238 stacktrace,
239 findit_for_crash.GetDepsInCrashStack(main_stack, crash_deps))
240
241 expected_dep_file_to_blame = {
242 'src/': {
243 'a.cc': dummy_blame
244 }
245 }
246
247 for dep, file_to_blame in dep_file_to_blame.iteritems():
248
249 self.assertTrue(dep in expected_dep_file_to_blame)
250
251 expected_file_to_blame = expected_dep_file_to_blame[dep]
252 for file_path, blame in file_to_blame.iteritems():
253 self.assertTrue(file_path in expected_file_to_blame)
254 expected_blame = expected_file_to_blame[file_path]
255
256 self._VerifyTwoBlamesEqual(blame, expected_blame)
257
258 def testFindMatchResults(self):
259 dep_file_to_changelogs = {
260 'src/': {
261 'a.cc': [
262 DUMMY_CHANGELOG1,
263 ]
264 }
265 }
266
267 dep_file_to_stack_infos = {
268 'src/': {
269 'a.cc': [
270 (StackFrame(0, 'src/', '', 'func', 'a.cc', [1]), 0),
271 (StackFrame(1, 'src/', '', 'func', 'a.cc', [7]), 0),
272 ],
273 'b.cc': [
274 (StackFrame(2, 'src/', '', 'func', 'b.cc', [36]), 0),
275 ]
276 }
277 }
278
279 dummy_blame = Blame('9', 'a.cc')
280 dummy_blame.AddRegion(
281 Region(1, 5, '6', 'a', 'a@chromium.org', 'Thu Mar 31 21:24:43 2016'))
282 dummy_blame.AddRegion(
283 Region(6, 10, '1', 'b', 'b@chromium.org', 'Thu Jun 19 12:11:40 2015'))
284
285 dep_file_to_blame = {
286 'src/': {
287 'a.cc': dummy_blame
288 }
289 }
290
291 expected_match_results = [{
292 'url': 'https://repo.test/+/1',
293 'revision': '1',
294 'dep_path': 'src/',
295 'component': '',
296 'author': 'r@chromium.org',
297 'time': 'Thu Mar 31 21:24:43 2016',
298 'reason': None,
299 'confidence': None,
300 }]
301
302 match_results = findit_for_crash.FindMatchResults(dep_file_to_changelogs,
303 dep_file_to_stack_infos,
304 dep_file_to_blame)
305 self.assertEqual([result.ToDict() for result in match_results],
306 expected_match_results)
307
308 def testFindItForCrashNoRegressionRange(self):
309 self.assertEqual(
310 findit_for_crash.FindItForCrash(Stacktrace(), {}, {}),
311 [])
312
313 def testFindItForCrashNoMatchFound(self):
314
315 def _MockFindMatchResults(*_):
316 return []
317
318 self.mock(findit_for_crash, 'FindMatchResults', _MockFindMatchResults)
319
320 regression_deps_rolls = {'src/': DependencyRoll('src/', 'https://repo',
321 '1', '2')}
322 self.assertEqual(findit_for_crash.FindItForCrash(
323 Stacktrace(), regression_deps_rolls, {}), [])
324
325 def testFindItForCrash(self):
326
327 def _MockFindMatchResults(*_):
328 match_result1 = MatchResult(DUMMY_CHANGELOG1, 'src/', '')
329 match_result1.file_to_stack_infos = {
330 'a.cc': [
331 (StackFrame(0, 'src/', '', 'func', 'a.cc', [1]), 0),
332 (StackFrame(1, 'src/', '', 'func', 'a.cc', [7]), 0),
333 ]
334 }
335 match_result1.min_distance = 0
336
337 match_result2 = MatchResult(DUMMY_CHANGELOG3, 'src/', '')
338 match_result2.file_to_stack_infos = {
339 'f.cc': [
340 (StackFrame(5, 'src/', '', 'func', 'f.cc', [1]), 0),
341 ]
342 }
343 match_result2.min_distance = 20
344
345 return [match_result1, match_result2]
346
347 self.mock(findit_for_crash, 'FindMatchResults', _MockFindMatchResults)
348
349 expected_match_results = [
350 {
351 'url': 'https://repo.test/+/1',
352 'revision': '1',
353 'dep_path': 'src/',
354 'component': '',
355 'author': 'r@chromium.org',
356 'time': 'Thu Mar 31 21:24:43 2016',
357 'reason': ('1. Top frame changed is frame #0 (score: 1)\n'
358 '2. Minimum distance to crashed line is 0 (score: 1)\n'
359 '\nChanged file a.cc which crashed in func (#0)'
360 ', func (#1)'),
361 'confidence': 1,
362 },
363 {
364 'url': 'https://repo.test/+/3',
365 'revision': '3',
366 'dep_path': 'src/',
367 'component': '',
368 'author': 'e@chromium.org',
369 'time': 'Thu Apr 1 21:24:43 2016',
370 'reason': ('1. Top frame changed is frame #5 (score: 0)\n'
371 '2. Minimum distance to crashed line is 20 (score: 0)\n'
372 '\nChanged file f.cc which crashed in func (#5)'),
373 'confidence': 0.22857142857142856,
374 },
375 ]
376
377 regression_deps_rolls = {'src/': DependencyRoll('src/', 'https://repo',
378 '1', '2')}
379
380 self.assertEqual(findit_for_crash.FindItForCrash(
381 Stacktrace(), regression_deps_rolls, {}), expected_match_results)
OLDNEW
« no previous file with comments | « appengine/findit/crash/test/crash_util_test.py ('k') | appengine/findit/crash/test/results_test.py » ('j') | no next file with comments »

Powered by Google App Engine
This is Rietveld 408576698