| Index: appengine/findit/crash/test/component_classifier_test.py
|
| diff --git a/appengine/findit/crash/test/component_classifier_test.py b/appengine/findit/crash/test/component_classifier_test.py
|
| index 527e2431fa69f7dec038a662d1d271d49ed264a5..59a065c5092cffa9746500794d4a963657d7acc4 100644
|
| --- a/appengine/findit/crash/test/component_classifier_test.py
|
| +++ b/appengine/findit/crash/test/component_classifier_test.py
|
| @@ -12,210 +12,72 @@ from crash.test.predator_testcase import PredatorTestCase
|
| from model.crash.crash_config import CrashConfig
|
| from libs.gitiles.change_log import ChangeLog
|
| from libs.gitiles.change_log import FileChangeInfo
|
| -
|
| -
|
| -# N.B., the call to Get() in CrashConfigComponentClassifier.__init__
|
| -# must only be executed from within the testFoo methods of
|
| -# ComponentClassifierTest. That is, we can't just do this once and for all
|
| -# when doing ComponentClassifierTest.__init__, because that'll cause some
|
| -# strange issues in mocking. But factoring it out like this so it gets
|
| -# (re)called ever time a testFoo is run, that works.
|
| -class CrashConfigComponentClassifier(ComponentClassifier):
|
| - """A ComponentClassifier which gets its components from CrashConfig."""
|
| - def __init__(self):
|
| - config = CrashConfig.Get().component_classifier
|
| - super(CrashConfigComponentClassifier, self).__init__(
|
| - [Component(name, path, function)
|
| - for path, function, name
|
| - in config.get('path_function_component', [])],
|
| - config.get('top_n', 0))
|
| +from libs.gitiles.diff import ChangeType
|
|
|
|
|
| class ComponentClassifierTest(PredatorTestCase):
|
| + """Tests ``ComponentClassifier`` class."""
|
|
|
| def setUp(self):
|
| super(ComponentClassifierTest, self).setUp()
|
| - # Only construct the cccc once, rather than making a new one every
|
| + config = CrashConfig.Get().component_classifier
|
| + components = [Component(component_name, path_regex, function_regex)
|
| + for path_regex, function_regex, component_name
|
| + in config['path_function_component']]
|
| + # Only construct the classifier once, rather than making a new one every
|
| # time we call a method on it.
|
| - self.cccc = CrashConfigComponentClassifier()
|
| -
|
| - def testGetClassFromStackFrame(self):
|
| - frame = StackFrame(0, 'src/', 'func', 'comp1.cc', 'src/comp1.cc', [2])
|
| - self.assertEqual(self.cccc.GetClassFromStackFrame(frame), 'Comp1>Dummy')
|
| -
|
| - frame = StackFrame(0, 'src/', 'func2', 'comp2.cc', 'src/comp2.cc', [32])
|
| - self.assertEqual(self.cccc.GetClassFromStackFrame(frame), 'Comp2>Dummy')
|
| -
|
| - frame = StackFrame(0, 'src/', 'no_func', 'comp2.cc', 'src/comp2.cc', [32])
|
| - self.assertEqual(self.cccc.GetClassFromStackFrame(frame), '')
|
| -
|
| - frame = StackFrame(0, 'src/', 'func2', 'a.cc', 'src/a.cc', [6])
|
| - self.assertEqual(self.cccc.GetClassFromStackFrame(frame), '')
|
| + self.classifier = ComponentClassifier(components, config['top_n'])
|
|
|
| - def testGetClassFromSuspect(self):
|
| - suspect = Suspect(self.GetDummyChangeLog(), 'src/')
|
| - self.assertEqual(self.cccc.GetClassFromSuspect(suspect), '')
|
| + def testClassifyCallStack(self):
|
| + """Tests ``ClassifyCallStack`` method."""
|
| + callstack = CallStack(
|
| + 0, [StackFrame(0, 'src/', 'func', 'comp1.cc', 'src/comp1.cc', [2])])
|
| + self.assertEqual(self.classifier.ClassifyCallStack(callstack),
|
| + ['Comp1>Dummy'])
|
|
|
| - suspect.file_to_stack_infos = {
|
| - 'comp1.cc': [
|
| - (StackFrame(0, 'src/', 'func', 'comp1.cc', 'src/comp1.cc', [2]), 0)
|
| - ]
|
| - }
|
| - self.assertEqual(self.cccc.GetClassFromSuspect(suspect), 'Comp1>Dummy')
|
| + callstack = CallStack(
|
| + 0, [StackFrame(0, 'dummy/', 'no_func', 'comp2.cc',
|
| + 'dummy/comp2.cc', [32])])
|
| + self.assertEqual(self.classifier.ClassifyCallStack(callstack), [])
|
|
|
| - def testClassifyCrashStack(self):
|
| crash_stack = CallStack(0, frame_list=[
|
| StackFrame(0, 'src/', 'func', 'comp1.cc', 'src/comp1.cc', [2]),
|
| StackFrame(1, 'src/', 'ff', 'comp1.cc', 'src/comp1.cc', [21]),
|
| StackFrame(2, 'src/', 'func2', 'comp2.cc', 'src/comp2.cc', [8])])
|
|
|
| - self.assertEqual(self.cccc.Classify([], crash_stack),
|
| + self.assertEqual(self.classifier.ClassifyCallStack(crash_stack),
|
| ['Comp1>Dummy', 'Comp2>Dummy'])
|
|
|
| - def testClassifySuspects(self):
|
| - suspect = Suspect(self.GetDummyChangeLog(), 'src/')
|
| - suspect.file_to_stack_infos = {
|
| - 'comp1.cc': [
|
| - (StackFrame(0, 'src/', 'func', 'comp1.cc', 'src/comp1.cc', [2]), 0)
|
| - ]
|
| - }
|
| -
|
| - self.assertEqual(self.cccc.Classify([suspect], CallStack(0)),
|
| - ['Comp1>Dummy'])
|
| -
|
| - def testClassifierDoNotHaveConfig(self):
|
| - crash_config = CrashConfig.Get()
|
| - crash_config.component_classifier = {}
|
| - # N.B., we must construct a new cccc here, becasue we changed CrashConfig.
|
| - self.cccc = CrashConfigComponentClassifier()
|
| -
|
| - crash_stack = CallStack(0, frame_list=[
|
| - StackFrame(0, 'src/', 'func', 'comp1.cc', 'src/comp1.cc', [2]),
|
| - StackFrame(1, 'src/', 'ff', 'comp1.cc', 'src/comp1.cc', [21]),
|
| - StackFrame(2, 'src/', 'func2', 'comp2.cc', 'src/comp2.cc', [8])])
|
| -
|
| + def testClassifySuspect(self):
|
| + """Tests ``ClassifySuspect`` method."""
|
| suspect = Suspect(self.GetDummyChangeLog(), 'src/')
|
| - suspect.file_to_stack_infos = {
|
| - 'comp1.cc': [
|
| - (StackFrame(0, 'src/', 'func', 'comp1.cc', 'src/comp1.cc', [2]), 0)
|
| - ]
|
| - }
|
| -
|
| - self.assertEqual(self.cccc.Classify([suspect], crash_stack), [])
|
| -
|
| - def testGetClassFromFileChangeInfo(self):
|
| - self.assertEqual(
|
| - CrashConfigComponentClassifier().GetClassFromFileChangeInfo(
|
| - FileChangeInfo.FromDict({'change_type': 'modify',
|
| - 'old_path': 'src/comp1.cc',
|
| - 'new_path': 'src/comp1.cc'})),
|
| - 'Comp1>Dummy')
|
| -
|
| - def testGetClassFromFileChangeInfoOldPath(self):
|
| - self.assertEqual(
|
| - CrashConfigComponentClassifier().GetClassFromFileChangeInfo(
|
| - FileChangeInfo.FromDict({'change_type': 'delete',
|
| - 'old_path': 'src/comp1.cc',
|
| - 'new_path': ''})),
|
| - 'Comp1>Dummy')
|
| + suspect.changelog = suspect.changelog._replace(
|
| + touched_files = [FileChangeInfo(ChangeType.MODIFY,
|
| + 'comp1.cc', 'comp1.cc')])
|
| + self.assertEqual(self.classifier.ClassifySuspect(suspect), ['Comp1>Dummy'])
|
| +
|
| + def testClassifyEmptySuspect(self):
|
| + """Tests ``ClassifySuspect`` returns None for empty suspect."""
|
| + self.assertIsNone(self.classifier.ClassifySuspect(None))
|
| +
|
| + def testClassifySuspectNoMatch(self):
|
| + """Tests ``ClassifySuspect`` returns None if there is no file match."""
|
| + suspect = Suspect(self.GetDummyChangeLog(), 'dummy')
|
| + suspect.changelog = suspect.changelog._replace(
|
| + touched_files = [FileChangeInfo(ChangeType.MODIFY,
|
| + 'comp1.cc', 'comp1.cc')])
|
| + self.assertEqual(self.classifier.ClassifySuspect(suspect), [])
|
|
|
| -
|
| - def testGetClassFromNoneFileChangeInfo(self):
|
| - self.assertEqual(
|
| - CrashConfigComponentClassifier().GetClassFromFileChangeInfo(None),
|
| - None)
|
| -
|
| - def testGetClassFromChangeFileInfoNoMapping(self):
|
| - self.assertEqual(
|
| - CrashConfigComponentClassifier().GetClassFromFileChangeInfo(
|
| - FileChangeInfo.FromDict({'change_type':'modify',
|
| - 'old_path':'file',
|
| - 'new_path':'file'})),'')
|
| -
|
| - def testGetClassFromChangeFileInfoNoMappingOldPath(self):
|
| - self.assertEqual(
|
| - CrashConfigComponentClassifier().GetClassFromFileChangeInfo(
|
| - FileChangeInfo.FromDict({'change_type':'rename',
|
| - 'old_path':'old_file',
|
| - 'new_path':'new_file'})),'')
|
| -
|
| - def testClassifyChangeLog(self):
|
| - change_log = ChangeLog.FromDict({
|
| - 'author': {
|
| - 'name': 'a',
|
| - 'email': 'b@email.com',
|
| - 'time': '2014-08-13 00:53:12',
|
| - },
|
| - 'committer': {
|
| - 'name': 'c',
|
| - 'email': 'd@email.com',
|
| - 'time': '2014-08-14 00:53:12',
|
| - },
|
| - 'revision': 'aaaa',
|
| - 'commit_position': 1111,
|
| - 'touched_files': [
|
| - {
|
| - 'change_type': 'copy',
|
| - 'old_path': 'file',
|
| - 'new_path': 'src/comp2.cc'
|
| - },
|
| - {
|
| - 'change_type': 'modify',
|
| - 'old_path': 'src/comp2.cc',
|
| - 'new_path': 'src/comp2.cc'
|
| - },
|
| - {
|
| - 'change_type': 'modify',
|
| - 'old_path': 'src/comp1.cc',
|
| - 'new_path': 'src/comp1.cc'
|
| - }
|
| - ],
|
| - 'message': 'blabla...',
|
| - 'commit_url':
|
| - 'https://chromium.googlesource.com/chromium/src/+/git_hash',
|
| - 'code_review_url': 'https://codereview.chromium.org/2222',
|
| - 'reverted_revision': '8d4a4fa6s18raf3re12tg6r'})
|
| - self.assertEqual(
|
| - CrashConfigComponentClassifier().ClassifyChangeLog(change_log),
|
| - ['Comp2>Dummy', 'Comp1>Dummy'])
|
| -
|
| - def testClassifyNoneChangeLog(self):
|
| - change_log = None
|
| - self.assertEqual(
|
| - CrashConfigComponentClassifier().ClassifyChangeLog(change_log),
|
| - None)
|
| -
|
| - def testClassifyChangeLogNoMapping(self):
|
| - change_log = ChangeLog.FromDict({
|
| - 'author': {
|
| - 'name': 'a',
|
| - 'email': 'b@email.com',
|
| - 'time': '2014-08-13 00:53:12',
|
| - },
|
| - 'committer': {
|
| - 'name': 'c',
|
| - 'email': 'd@email.com',
|
| - 'time': '2014-08-14 00:53:12',
|
| - },
|
| - 'revision': 'aaaa',
|
| - 'commit_position': 1111,
|
| - 'touched_files': [
|
| - {
|
| - 'change_type': 'rename',
|
| - 'old_path': 'old_file',
|
| - 'new_path': 'new_file'
|
| - },
|
| - {
|
| - 'change_type': 'delete',
|
| - 'old_path': 'file',
|
| - 'new_path': 'file'
|
| - }
|
| - ],
|
| - 'message': 'blabla...',
|
| - 'commit_url':
|
| - 'https://chromium.googlesource.com/chromium/src/+/git_hash',
|
| - 'code_review_url': 'https://codereview.chromium.org/2222',
|
| - 'reverted_revision': '8d4a4fa6s18raf3re12tg6r'})
|
| - self.assertEqual(
|
| - CrashConfigComponentClassifier().ClassifyChangeLog(change_log),
|
| - [])
|
| + def testClassifySuspects(self):
|
| + """Tests ``ClassifySuspects`` classify a list of ``Suspect``s."""
|
| + suspect1 = Suspect(self.GetDummyChangeLog(), 'src/')
|
| + suspect1.changelog = suspect1.changelog._replace(
|
| + touched_files = [FileChangeInfo(ChangeType.MODIFY,
|
| + 'comp1.cc', 'comp1.cc')])
|
| + suspect2 = Suspect(self.GetDummyChangeLog(), 'src/')
|
| + suspect2.changelog = suspect2.changelog._replace(
|
| + touched_files = [FileChangeInfo(ChangeType.MODIFY,
|
| + 'comp2.cc', 'comp2.cc')])
|
| +
|
| + self.assertEqual(self.classifier.ClassifySuspects([suspect1, suspect2]),
|
| + ['Comp1>Dummy', 'Comp2>Dummy'])
|
|
|