| OLD | NEW |
| 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 collections import defaultdict | 5 from collections import defaultdict |
| 6 | 6 |
| 7 from common.blame import Blame | |
| 8 from common.blame import Region | |
| 9 from common.change_log import ChangeLog | |
| 10 from common.dependency import Dependency | 7 from common.dependency import Dependency |
| 11 from common.dependency import DependencyRoll | 8 from common.dependency import DependencyRoll |
| 12 from common.git_repository import GitRepository | |
| 13 from common.http_client_appengine import HttpClientAppengine | 9 from common.http_client_appengine import HttpClientAppengine |
| 14 from common import chrome_dependency_fetcher | 10 from common import chrome_dependency_fetcher |
| 15 from common import git_repository | |
| 16 from crash.crash_report import CrashReport | 11 from crash.crash_report import CrashReport |
| 17 from crash import changelist_classifier | 12 from crash import changelist_classifier |
| 18 from crash.results import MatchResult | 13 from crash.results import MatchResult |
| 19 from crash.stacktrace import CallStack | 14 from crash.stacktrace import CallStack |
| 20 from crash.stacktrace import StackFrame | 15 from crash.stacktrace import StackFrame |
| 21 from crash.stacktrace import Stacktrace | 16 from crash.stacktrace import Stacktrace |
| 22 from crash.test.crash_test_suite import CrashTestSuite | 17 from crash.test.crash_test_suite import CrashTestSuite |
| 18 from lib.gitiles.blame import Blame |
| 19 from lib.gitiles.blame import Region |
| 20 from lib.gitiles.change_log import ChangeLog |
| 21 from lib.gitiles.gitiles_repository import GitilesRepository |
| 23 | 22 |
| 24 DUMMY_CHANGELOG1 = ChangeLog.FromDict({ | 23 DUMMY_CHANGELOG1 = ChangeLog.FromDict({ |
| 25 'author_name': 'r@chromium.org', | 24 'author_name': 'r@chromium.org', |
| 26 'message': 'dummy', | 25 'message': 'dummy', |
| 27 'committer_email': 'r@chromium.org', | 26 'committer_email': 'r@chromium.org', |
| 28 'commit_position': 175900, | 27 'commit_position': 175900, |
| 29 'author_email': 'r@chromium.org', | 28 'author_email': 'r@chromium.org', |
| 30 'touched_files': [ | 29 'touched_files': [ |
| 31 { | 30 { |
| 32 'change_type': 'add', | 31 'change_type': 'add', |
| (...skipping 102 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
| 135 } | 134 } |
| 136 | 135 |
| 137 stack_deps = { | 136 stack_deps = { |
| 138 'src/': Dependency('src/', 'https://url_src', 'rev1', 'DEPS'), | 137 'src/': Dependency('src/', 'https://url_src', 'rev1', 'DEPS'), |
| 139 'src/new': Dependency('src/new', 'https://new', 'rev2', 'DEPS'), | 138 'src/new': Dependency('src/new', 'https://new', 'rev2', 'DEPS'), |
| 140 } | 139 } |
| 141 | 140 |
| 142 def _MockGetChangeLogs(*_): | 141 def _MockGetChangeLogs(*_): |
| 143 return [DUMMY_CHANGELOG1, DUMMY_CHANGELOG2, DUMMY_CHANGELOG3] | 142 return [DUMMY_CHANGELOG1, DUMMY_CHANGELOG2, DUMMY_CHANGELOG3] |
| 144 | 143 |
| 145 self.mock(git_repository.GitRepository, 'GetChangeLogs', _MockGetChangeLogs) | 144 self.mock(GitilesRepository, 'GetChangeLogs', _MockGetChangeLogs) |
| 146 | 145 |
| 147 dep_file_to_changelogs, ignore_cls = ( | 146 dep_file_to_changelogs, ignore_cls = ( |
| 148 changelist_classifier.GetChangeLogsForFilesGroupedByDeps( | 147 changelist_classifier.GetChangeLogsForFilesGroupedByDeps( |
| 149 regression_deps_rolls, stack_deps, git_repository.GitRepository())) | 148 regression_deps_rolls, stack_deps, GitilesRepository())) |
| 150 dep_file_to_changelogs_json = defaultdict(lambda: defaultdict(list)) | 149 dep_file_to_changelogs_json = defaultdict(lambda: defaultdict(list)) |
| 151 for dep, file_to_changelogs in dep_file_to_changelogs.iteritems(): | 150 for dep, file_to_changelogs in dep_file_to_changelogs.iteritems(): |
| 152 for file_path, changelogs in file_to_changelogs.iteritems(): | 151 for file_path, changelogs in file_to_changelogs.iteritems(): |
| 153 for changelog in changelogs: | 152 for changelog in changelogs: |
| 154 dep_file_to_changelogs_json[dep][file_path].append(changelog.ToDict()) | 153 dep_file_to_changelogs_json[dep][file_path].append(changelog.ToDict()) |
| 155 | 154 |
| 156 expected_dep_file_to_changelogs_json = { | 155 expected_dep_file_to_changelogs_json = { |
| 157 'src/': { | 156 'src/': { |
| 158 'a.cc': [DUMMY_CHANGELOG1.ToDict()], | 157 'a.cc': [DUMMY_CHANGELOG1.ToDict()], |
| 159 'f.cc': [DUMMY_CHANGELOG3.ToDict()] | 158 'f.cc': [DUMMY_CHANGELOG3.ToDict()] |
| (...skipping 71 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
| 231 ] | 230 ] |
| 232 } | 231 } |
| 233 } | 232 } |
| 234 | 233 |
| 235 dummy_blame = Blame('9', 'a.cc') | 234 dummy_blame = Blame('9', 'a.cc') |
| 236 dummy_blame.AddRegion( | 235 dummy_blame.AddRegion( |
| 237 Region(1, 5, '6', 'a', 'a@chromium.org', 'Thu Mar 31 21:24:43 2016')) | 236 Region(1, 5, '6', 'a', 'a@chromium.org', 'Thu Mar 31 21:24:43 2016')) |
| 238 dummy_blame.AddRegion( | 237 dummy_blame.AddRegion( |
| 239 Region(6, 10, '1', 'b', 'b@chromium.org', 'Thu Jun 19 12:11:40 2015')) | 238 Region(6, 10, '1', 'b', 'b@chromium.org', 'Thu Jun 19 12:11:40 2015')) |
| 240 | 239 |
| 241 self.mock(GitRepository, 'GetBlame', lambda *_: dummy_blame) | 240 self.mock(GitilesRepository, 'GetBlame', lambda *_: dummy_blame) |
| 242 | 241 |
| 243 stack_deps = { | 242 stack_deps = { |
| 244 'src/': Dependency('src/', 'https://url_src', 'rev1', 'DEPS'), | 243 'src/': Dependency('src/', 'https://url_src', 'rev1', 'DEPS'), |
| 245 } | 244 } |
| 246 | 245 |
| 247 expected_match_results = [{ | 246 expected_match_results = [{ |
| 248 'url': 'https://repo.test/+/1', | 247 'url': 'https://repo.test/+/1', |
| 249 'review_url': 'https://codereview.chromium.org/3281', | 248 'review_url': 'https://codereview.chromium.org/3281', |
| 250 'revision': '1', | 249 'revision': '1', |
| 251 'project_path': 'src/', | 250 'project_path': 'src/', |
| 252 'author': 'r@chromium.org', | 251 'author': 'r@chromium.org', |
| 253 'time': 'Thu Mar 31 21:24:43 2016', | 252 'time': 'Thu Mar 31 21:24:43 2016', |
| 254 'reasons': None, | 253 'reasons': None, |
| 255 'confidence': None, | 254 'confidence': None, |
| 256 'changed_files': None | 255 'changed_files': None |
| 257 }] | 256 }] |
| 258 | 257 |
| 259 match_results = changelist_classifier.FindMatchResults( | 258 match_results = changelist_classifier.FindMatchResults( |
| 260 dep_file_to_changelogs, dep_file_to_stack_infos, stack_deps, | 259 dep_file_to_changelogs, dep_file_to_stack_infos, stack_deps, |
| 261 git_repository.GitRepository()) | 260 GitilesRepository()) |
| 262 self.assertListEqual([result.ToDict() for result in match_results], | 261 self.assertListEqual([result.ToDict() for result in match_results], |
| 263 expected_match_results) | 262 expected_match_results) |
| 264 | 263 |
| 265 # TODO(http://crbug.com/659346): why do these mocks give coverage | 264 # TODO(http://crbug.com/659346): why do these mocks give coverage |
| 266 # failures? That's almost surely hiding a bug in the tests themselves. | 265 # failures? That's almost surely hiding a bug in the tests themselves. |
| 267 def testFindItForCrashNoRegressionRange(self): # pragma: no cover | 266 def testFindItForCrashNoRegressionRange(self): # pragma: no cover |
| 268 self.mock(chrome_dependency_fetcher.ChromeDependencyFetcher, | 267 self.mock(chrome_dependency_fetcher.ChromeDependencyFetcher, |
| 269 'GetDependencyRollsDict', lambda *_: {}) | 268 'GetDependencyRollsDict', lambda *_: {}) |
| 270 self.mock(chrome_dependency_fetcher.ChromeDependencyFetcher, | 269 self.mock(chrome_dependency_fetcher.ChromeDependencyFetcher, |
| 271 'GetDependency', lambda *_: {}) | 270 'GetDependency', lambda *_: {}) |
| 272 cl_classifier = changelist_classifier.ChangelistClassifier(7, | 271 cl_classifier = changelist_classifier.ChangelistClassifier(7, |
| 273 git_repository.GitRepository()) | 272 GitilesRepository()) |
| 274 # N.B., for this one test we really do want regression_range=None. | 273 # N.B., for this one test we really do want regression_range=None. |
| 275 report = DUMMY_REPORT._replace(regression_range=None) | 274 report = DUMMY_REPORT._replace(regression_range=None) |
| 276 self.assertListEqual(cl_classifier(report), []) | 275 self.assertListEqual(cl_classifier(report), []) |
| 277 | 276 |
| 278 def testFindItForCrashNoMatchFound(self): | 277 def testFindItForCrashNoMatchFound(self): |
| 279 self.mock(changelist_classifier, 'FindMatchResults', lambda *_: []) | 278 self.mock(changelist_classifier, 'FindMatchResults', lambda *_: []) |
| 280 self.mock(chrome_dependency_fetcher.ChromeDependencyFetcher, | 279 self.mock(chrome_dependency_fetcher.ChromeDependencyFetcher, |
| 281 'GetDependencyRollsDict', | 280 'GetDependencyRollsDict', |
| 282 lambda *_: {'src/': DependencyRoll('src/', 'https://repo', '1', '2')}) | 281 lambda *_: {'src/': DependencyRoll('src/', 'https://repo', '1', '2')}) |
| 283 self.mock(chrome_dependency_fetcher.ChromeDependencyFetcher, | 282 self.mock(chrome_dependency_fetcher.ChromeDependencyFetcher, |
| 284 'GetDependency', lambda *_: {}) | 283 'GetDependency', lambda *_: {}) |
| 285 cl_classifier = changelist_classifier.ChangelistClassifier(7, | 284 cl_classifier = changelist_classifier.ChangelistClassifier(7, |
| 286 git_repository.GitRepository()) | 285 GitilesRepository()) |
| 287 self.assertListEqual(cl_classifier(DUMMY_REPORT), []) | 286 self.assertListEqual(cl_classifier(DUMMY_REPORT), []) |
| 288 | 287 |
| 289 def testFindItForCrash(self): | 288 def testFindItForCrash(self): |
| 290 | 289 |
| 291 def _MockFindMatchResults(*_): | 290 def _MockFindMatchResults(*_): |
| 292 match_result1 = MatchResult(DUMMY_CHANGELOG1, 'src/', '') | 291 match_result1 = MatchResult(DUMMY_CHANGELOG1, 'src/', '') |
| 293 frame1 = StackFrame(0, 'src/', 'func', 'a.cc', 'src/a.cc', [1]) | 292 frame1 = StackFrame(0, 'src/', 'func', 'a.cc', 'src/a.cc', [1]) |
| 294 frame2 = StackFrame(1, 'src/', 'func', 'a.cc', 'src/a.cc', [7]) | 293 frame2 = StackFrame(1, 'src/', 'func', 'a.cc', 'src/a.cc', [7]) |
| 295 match_result1.file_to_stack_infos = { | 294 match_result1.file_to_stack_infos = { |
| 296 'a.cc': [(frame1, 0), (frame2, 0)] | 295 'a.cc': [(frame1, 0), (frame2, 0)] |
| (...skipping 13 matching lines...) Expand all Loading... |
| 310 | 309 |
| 311 return [match_result1, match_result2] | 310 return [match_result1, match_result2] |
| 312 | 311 |
| 313 self.mock(changelist_classifier, 'FindMatchResults', _MockFindMatchResults) | 312 self.mock(changelist_classifier, 'FindMatchResults', _MockFindMatchResults) |
| 314 self.mock(chrome_dependency_fetcher.ChromeDependencyFetcher, | 313 self.mock(chrome_dependency_fetcher.ChromeDependencyFetcher, |
| 315 'GetDependencyRollsDict', | 314 'GetDependencyRollsDict', |
| 316 lambda *_: {'src/': DependencyRoll('src/', 'https://repo', '1', '2')}) | 315 lambda *_: {'src/': DependencyRoll('src/', 'https://repo', '1', '2')}) |
| 317 self.mock(chrome_dependency_fetcher.ChromeDependencyFetcher, | 316 self.mock(chrome_dependency_fetcher.ChromeDependencyFetcher, |
| 318 'GetDependency', lambda *_: {}) | 317 'GetDependency', lambda *_: {}) |
| 319 cl_classifier = changelist_classifier.ChangelistClassifier(7, | 318 cl_classifier = changelist_classifier.ChangelistClassifier(7, |
| 320 git_repository.GitRepository()) | 319 GitilesRepository()) |
| 321 results = cl_classifier(DUMMY_REPORT) | 320 results = cl_classifier(DUMMY_REPORT) |
| 322 expected_match_results = [ | 321 expected_match_results = [ |
| 323 { | 322 { |
| 324 'reasons': [('TopFrameIndex', 1.0, 'Top frame is #0'), | 323 'reasons': [('TopFrameIndex', 1.0, 'Top frame is #0'), |
| 325 ('MinDistance', 1, 'Minimum distance is 0')], | 324 ('MinDistance', 1, 'Minimum distance is 0')], |
| 326 'changed_files': [{'info': 'Minimum distance (LOC) 0, frame #0', | 325 'changed_files': [{'info': 'Minimum distance (LOC) 0, frame #0', |
| 327 'blame_url': None, 'file': 'a.cc'}], | 326 'blame_url': None, 'file': 'a.cc'}], |
| 328 'time': 'Thu Mar 31 21:24:43 2016', | 327 'time': 'Thu Mar 31 21:24:43 2016', |
| 329 'author': 'r@chromium.org', | 328 'author': 'r@chromium.org', |
| 330 'url': 'https://repo.test/+/1', | 329 'url': 'https://repo.test/+/1', |
| (...skipping 38 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
| 369 return [match_result1, match_result2, match_result3] | 368 return [match_result1, match_result2, match_result3] |
| 370 | 369 |
| 371 self.mock(changelist_classifier, 'FindMatchResults', _MockFindMatchResults) | 370 self.mock(changelist_classifier, 'FindMatchResults', _MockFindMatchResults) |
| 372 self.mock(chrome_dependency_fetcher.ChromeDependencyFetcher, | 371 self.mock(chrome_dependency_fetcher.ChromeDependencyFetcher, |
| 373 'GetDependencyRollsDict', | 372 'GetDependencyRollsDict', |
| 374 lambda *_: {'src/': DependencyRoll('src/', 'https://repo', '1', '2')}) | 373 lambda *_: {'src/': DependencyRoll('src/', 'https://repo', '1', '2')}) |
| 375 self.mock(chrome_dependency_fetcher.ChromeDependencyFetcher, | 374 self.mock(chrome_dependency_fetcher.ChromeDependencyFetcher, |
| 376 'GetDependency', lambda *_: {}) | 375 'GetDependency', lambda *_: {}) |
| 377 | 376 |
| 378 cl_classifier = changelist_classifier.ChangelistClassifier(7, | 377 cl_classifier = changelist_classifier.ChangelistClassifier(7, |
| 379 git_repository.GitRepository()) | 378 GitilesRepository()) |
| 380 results = cl_classifier(DUMMY_REPORT) | 379 results = cl_classifier(DUMMY_REPORT) |
| 381 expected_match_results = [ | 380 expected_match_results = [ |
| 382 { | 381 { |
| 383 'author': 'r@chromium.org', | 382 'author': 'r@chromium.org', |
| 384 'changed_files': [ | 383 'changed_files': [ |
| 385 { | 384 { |
| 386 'blame_url': None, | 385 'blame_url': None, |
| 387 'file': 'a.cc', | 386 'file': 'a.cc', |
| 388 'info': 'Minimum distance (LOC) 1, frame #0' | 387 'info': 'Minimum distance (LOC) 1, frame #0' |
| 389 } | 388 } |
| (...skipping 38 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
| 428 return [match_result1, match_result2] | 427 return [match_result1, match_result2] |
| 429 | 428 |
| 430 self.mock(changelist_classifier, 'FindMatchResults', _MockFindMatchResults) | 429 self.mock(changelist_classifier, 'FindMatchResults', _MockFindMatchResults) |
| 431 self.mock(chrome_dependency_fetcher.ChromeDependencyFetcher, | 430 self.mock(chrome_dependency_fetcher.ChromeDependencyFetcher, |
| 432 'GetDependencyRollsDict', | 431 'GetDependencyRollsDict', |
| 433 lambda *_: {'src/': DependencyRoll('src/', 'https://repo', '1', '2')}) | 432 lambda *_: {'src/': DependencyRoll('src/', 'https://repo', '1', '2')}) |
| 434 self.mock(chrome_dependency_fetcher.ChromeDependencyFetcher, | 433 self.mock(chrome_dependency_fetcher.ChromeDependencyFetcher, |
| 435 'GetDependency', lambda *_: {}) | 434 'GetDependency', lambda *_: {}) |
| 436 | 435 |
| 437 cl_classifier = changelist_classifier.ChangelistClassifier(7, | 436 cl_classifier = changelist_classifier.ChangelistClassifier(7, |
| 438 git_repository.GitRepository()) | 437 GitilesRepository()) |
| 439 self.assertListEqual(cl_classifier(DUMMY_REPORT), []) | 438 self.assertListEqual(cl_classifier(DUMMY_REPORT), []) |
| OLD | NEW |