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

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

Powered by Google App Engine
This is Rietveld 408576698