Пример #1
0
    def testFileChangeinfoChangedPathProperty(self):
        """Test ``changed_file`` property of ``FileChangeInfo``."""
        modified_file = FileChangeInfo.Modify('a.cc')
        self.assertEqual(modified_file.changed_path, 'a.cc')

        added_file = FileChangeInfo.Modify('a.cc')
        self.assertEqual(added_file.changed_path, 'a.cc')

        copied_file = FileChangeInfo.Copy('old.cc', 'new.cc')
        self.assertEqual(copied_file.changed_path, 'new.cc')

        deleted_file = FileChangeInfo.Delete('old.cc')
        self.assertEqual(deleted_file.changed_path, 'old.cc')
    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/a.cc', 'comp1/b.cc')
        ])
        suspect2 = Suspect(self.GetDummyChangeLog(), 'src/')
        suspect2.changelog = suspect2.changelog._replace(touched_files=[
            FileChangeInfo(ChangeType.MODIFY, 'comp2/a.cc', 'comp2/b.cc')
        ])

        self.assertEqual(
            self.classifier.ClassifySuspects([suspect1, suspect2]),
            ['Comp1>Dummy', 'Comp2>Dummy'])
Пример #3
0
  def testMinDistanceFeatureInfinityDistance(self):
    """Test that we return log(0) when the min_distance is infinity.

    The infinity distance means the touched file get overwritten by other
    cls, and the change didn't show in the final blame file.
    """
    report = self._GetDummyReport(
        deps={'src/': Dependency('src/', 'https://repo', '6')},
        dep_rolls={'src/': DependencyRoll('src/', 'https://repo', '0', '4')})
    suspect = self._GetMockSuspect()
    crashed = CrashedFile(_MOCK_FRAME)
    matches = {
        crashed:
        CrashMatch(crashed,
                   [FileChangeInfo(ChangeType.MODIFY, 'file', 'file')],
                   [FrameInfo(_MOCK_FRAME, 0)])
    }

    with mock.patch('analysis.linear.changelist_features.min_distance.'
                    'MinDistanceFeature.'
                    'DistanceBetweenTouchedFileAndFrameInfos') as mock_distance:
      mock_distance.return_value = None
      self.assertEqual(
          0.0,
          min_distance.MinDistanceFeature(
              self._get_repository, _MAXIMUM)(report)(suspect, matches).value)

    with mock.patch('analysis.linear.changelist_features.min_distance.'
                    'MinDistanceFeature.'
                    'DistanceBetweenTouchedFileAndFrameInfos') as mock_distance:
      mock_distance.return_value = min_distance.Distance(float('inf'), None)
      self.assertEqual(
          0.0,
          min_distance.MinDistanceFeature(self._get_repository, 100)(report)(
              suspect, matches).value)
 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), [])
Пример #5
0
 def testClassifyTouchedFile(self):
     """Tests ``ClassifyTouchedFile`` method."""
     touched_file = FileChangeInfo(ChangeType.MODIFY, 'comp1/a.cc',
                                   'comp1/b.cc')
     self.assertEqual(
         self.classifier.ClassifyTouchedFile('src', touched_file),
         'Comp1>Dummy')
Пример #6
0
    def testMinDistanceFeatureMiddling(self):
        """Test that the feature returns middling scores for middling distances."""
        report = self._GetDummyReport(
            deps={'src/': Dependency('src/', 'https://repo', '6')},
            dep_rolls={
                'src/': DependencyRoll('src/', 'https://repo', '0', '4')
            })

        frame = StackFrame(0, 'src/', 'func', 'f.cc', 'f.cc', [232],
                           'https://repo')
        distance = 42.
        crashed = CrashedFile('file')
        matches = {
            crashed:
            CrashMatch(crashed,
                       [FileChangeInfo(ChangeType.MODIFY, 'file', 'file')],
                       [FrameInfo(frame, 0)])
        }
        with mock.patch(
                'analysis.linear.changelist_features.'
                'min_distance.MinDistanceFeature.'
                'DistanceBetweenTouchedFileAndFrameInfos') as mock_distance:
            mock_distance.return_value = min_distance.Distance(distance, frame)
            self.assertEqual((_MAXIMUM - distance) / _MAXIMUM,
                             min_distance.MinDistanceFeature(
                                 self._get_repository,
                                 _MAXIMUM)(report)(self._GetMockSuspect(),
                                                   matches).value)
Пример #7
0
    def testMinDistanceFeatureIsOverMax(self):
        """Test that we return log(0) when the min_distance is too large."""
        report = self._GetDummyReport(
            deps={'src/': Dependency('src/', 'https://repo', '6')},
            dep_rolls={
                'src/': DependencyRoll('src/', 'https://repo', '0', '4')
            })

        distance = _MAXIMUM + 1
        frame = _MOCK_FRAME._replace(file_path='file')
        crashed = CrashedFile('file')
        matches = {
            crashed:
            CrashMatch(crashed,
                       [FileChangeInfo(ChangeType.MODIFY, 'file', 'file')],
                       [FrameInfo(frame, 0)])
        }
        with mock.patch(
                'analysis.linear.changelist_features.'
                'min_distance.MinDistanceFeature.'
                'DistanceBetweenTouchedFileAndFrameInfos') as mock_distance:
            mock_distance.return_value = min_distance.Distance(distance, None)
            self.assertEqual(
                0.0,
                min_distance.MinDistanceFeature(
                    self._get_repository,
                    _MAXIMUM)(report)(self._GetMockSuspect(), matches).value)
Пример #8
0
 def testClassifySuspectNoTouchedFileMatch(self):
     """Tests ``ClassifySuspect`` returns None if there is no file match."""
     suspect = Suspect(self.GetDummyChangeLog(), 'dummy')
     suspect.touched_files = [
         FileChangeInfo(ChangeType.MODIFY, 'a/b.h', 'a/b.h')
     ]
     self.assertIsNone(self.classifier.ClassifySuspect(suspect))
    def testCheckFileSameLineChanged(self):
        def MockGetChangedLines(*_):
            return [1, 3]

        self.mock(build_failure_analysis, '_GetChangedLinesForChromiumRepo',
                  MockGetChangedLines)
        touched_file = FileChangeInfo.FromDict({
            'change_type': ChangeType.MODIFY,
            'old_path': 'a/b/c.cc',
            'new_path': 'a/b/c.cc'
        })
        file_path_in_log = 'a/b/c.cc'
        justification = build_failure_analysis._Justification()
        file_name_occurrences = {'c.cc': 1}
        line_numbers = [1, 3]
        repo_info = {
            'repo_url': 'https://chromium.googlesource.com/chromium/src.git',
            'revision': 'dummy_abcd1234'
        }
        commit_revision = 'dummy_1'
        build_failure_analysis._CheckFile(touched_file, file_path_in_log,
                                          justification, file_name_occurrences,
                                          line_numbers, repo_info,
                                          commit_revision)

        expected_justification = {
            'score': 4,
            'hints': {
                'modified c.cc[1, 3] (and it was in log)': 4
            }
        }
        self.assertEqual(expected_justification, justification.ToDict())
Пример #10
0
  def testMinDistanceChangedFiles(self):
    """Tests ``ChangedFile`` method."""
    report = self._GetDummyReport(
        deps={'src/': Dependency('src/', 'https://repo', '6')},
        dep_rolls={'src/': DependencyRoll('src/', 'https://repo', '0', '4')})

    distance = 42
    crashed = CrashedFile(_MOCK_FRAME)
    matches = {
        crashed:
        CrashMatch(crashed,
                   [FileChangeInfo(ChangeType.MODIFY, 'file', 'file')],
                   [FrameInfo(_MOCK_FRAME, 0)])
    }
    frame = StackFrame(0, 'src/', 'func', 'f.cc', 'f.cc', [7], 'https://repo')
    with mock.patch('analysis.linear.changelist_features.min_distance.'
                    'MinDistanceFeature.'
                    'DistanceBetweenTouchedFileAndFrameInfos') as mock_distance:
      mock_distance.return_value = min_distance.Distance(distance, frame)
      self.assertEqual(
          min_distance.MinDistanceFeature(
              self._get_repository, _MAXIMUM)(report)(
              self._GetMockSuspect(), matches).changed_files,
              [ChangedFile(name='file',
                           blame_url=('%s/+blame/%s/f.cc#%d' %
                                      (frame.repo_url,
                                       report.crashed_version,
                                       frame.crashed_line_numbers[0])),
                           reasons=['Distance between touched lines and crashed'
                                    ' lines is %d, in frame #%d' % (
                                        distance, frame.index)])])
Пример #11
0
  def testDistanceBetweenTouchedFileAndFrameInfos(self):
    """Tests ``DistanceBetweenTouchedFileAndFrameInfos`` method."""
    feature = min_distance.MinDistanceFeature(self._get_repository, _MAXIMUM)
    frame1 = StackFrame(0, 'src/', 'func', 'a.cc', 'src/a.cc', [7],
                        repo_url='https://repo_url')
    frame2 = StackFrame(0, 'src/', 'func', 'a.cc', 'src/a.cc', [17],
                        repo_url='https://repo_url')
    touched_file = FileChangeInfo(ChangeType.MODIFY, 'file', 'file')

    blame = Blame('rev', 'src/')
    blame.AddRegions([Region(0, 10, 'rev', 'a1', 'e1', 't1'),
                      Region(11, 20, 'dummy_rev', 'a2', 'e2', 't2')])

    url_to_blame = {'rev/file': blame}

    def _MockGetBlame(path, revision):
      revision_path = '%s/%s' % (revision, path)
      return url_to_blame.get(revision_path)

    with mock.patch('libs.gitiles.gitiles_repository.GitilesRepository.'
                    'GetBlame') as mock_get_blame:
      mock_get_blame.side_effect = _MockGetBlame

      distance_info = feature.DistanceBetweenTouchedFileAndFrameInfos(
          'rev', touched_file, [FrameInfo(frame1, 0), FrameInfo(frame2, 0)],
           Dependency('src/', 'https://repo', 'rev'))
      self.assertEqual(distance_info, min_distance.Distance(0, frame1))

      distance_info = feature.DistanceBetweenTouchedFileAndFrameInfos(
          'wrong_rev', touched_file, [FrameInfo(frame1, 0),
                                      FrameInfo(frame2, 0)],
           Dependency('src/', 'https://repo', 'wrong_rev'))
      self.assertIsNone(distance_info)
 def testClassifySuspect(self):
     """Tests ``ClassifySuspect`` method."""
     suspect = Suspect(self.GetDummyChangeLog(), 'src/')
     suspect.changelog = suspect.changelog._replace(touched_files=[
         FileChangeInfo(ChangeType.MODIFY, 'comp1/a.cc', 'comp1/b.cc')
     ])
     self.assertEqual(self.classifier.ClassifySuspect(suspect),
                      ['Comp1>Dummy'])
Пример #13
0
 def testFileChangeinfo(self):
     filechange_dict = {
         'change_type': 'copy',
         'old_path': 'a',
         'new_path': 'b'
     }
     filechange_info = FileChangeInfo.FromDict(filechange_dict)
     self.assertEqual(filechange_dict, filechange_info.ToDict())
 def testMatchWhenCrashedDirectryIsEmpty(self):
     """Tests ``Match`` returns False when the crashed directory is empty."""
     self.assertFalse(
         self._feature.Match(
             None,
             FileChangeInfo.FromDict({
                 'change_type': 'add',
                 'new_path': 'p/a.cc',
                 'old_path': None,
             })))
Пример #15
0
  def testOnlyOneTouchedFilePerMatchedCrashedFile(self):
    """Test that ``CrashMatch`` can only have 1 touched file."""
    report = self._GetDummyReport(
        deps={'src/': Dependency('src/', 'https://repo', '6')},
        dep_rolls={'src/': DependencyRoll('src/', 'https://repo', '0', '4')})

    frame = _MOCK_FRAME._replace(file_path='file')
    crashed = CrashedFile('file')
    matches = {
        crashed:
        CrashMatch(crashed,
                   [FileChangeInfo(ChangeType.MODIFY, 'file', 'file'),
                    FileChangeInfo(ChangeType.MODIFY, 'dummy', 'dummy')],
                   [FrameInfo(frame, 0)])
    }
    self.assertEqual(
        0.0,
        min_distance.MinDistanceFeature(self._get_repository, _MAXIMUM)(report)(
            self._GetMockSuspect(), matches).value)
  def testCall(self):
    """Tests ``__call__`` method."""
    suspect = Suspect(self.GetDummyChangeLog(), 'src/')

    touched_file = FileChangeInfo.FromDict({'old_path': None,
                                            'new_path': 'a.cc',
                                            'change_type': 'add'})
    suspect.changelog = suspect.changelog._replace(
        touched_files=[touched_file]*15)
    self.assertEqual(self._feature(None)(suspect).value, 0.0)
Пример #17
0
    def testDistanceBetweenTouchedFileAndFrameInfosWithDeletedFile(self):
        """Tests that this method returns None when the touched_file is deleted."""
        feature = min_distance.MinDistanceFeature(self._get_repository,
                                                  _MAXIMUM)
        touched_file = FileChangeInfo(ChangeType.DELETE, 'file', None)

        distance_info = feature.DistanceBetweenTouchedFileAndFrameInfos(
            'rev', touched_file, [FrameInfo(_MOCK_FRAME, 0)],
            Dependency('src/', 'https://repo', 'rev'))

        self.assertIsNone(distance_info)
Пример #18
0
def GetFileChangeInfo(change_type, path1, path2):
    """Set old/new path and old/new mode."""
    change_type = change_type.lower()
    if change_type == ChangeType.MODIFY:
        return FileChangeInfo.Modify(path1)

    if change_type == ChangeType.ADD:
        return FileChangeInfo.Add(path1)

    if change_type == ChangeType.DELETE:
        return FileChangeInfo.Delete(path1)

    if change_type == ChangeType.RENAME:
        return FileChangeInfo.Rename(path1, path2)

    # TODO(http://crbug.com/659346): write coverage test for this branch
    if change_type.lower() == ChangeType.COPY:  # pragma: no cover
        return FileChangeInfo.Copy(path1, path2)

    return None
    def testFilePathMatchAfterFileRename(self):
        """Tests the feature can match old file with new file after file name."""
        feature = TouchCrashedDirectoryBaseFeature(
            options={'replace_path': {
                'old/dir': 'new/dir'
            }})

        self.assertTrue(
            feature.Match(
                CrashedDirectory('new/dir/a'),
                FileChangeInfo(ChangeType.MODIFY, 'old/dir/a/FileName.cc',
                               'old/dir/a/FileName.cc')))
 def testFeatureValueIsOneWhenThereIsMatchedDirectory(self):
     """Test that feature value is 1 when there is matched directory."""
     changelog = self.GetDummyChangeLog()._replace(touched_files=[
         FileChangeInfo.FromDict({
             'change_type': 'add',
             'new_path': 'p/a.cc',
             'old_path': None,
         })
     ])
     suspect = Suspect(changelog, 'src/')
     feature_value = self._feature(self._report)(suspect)
     self.assertEqual(1.0, feature_value.value)
    def testFilePathMatchAfterReplacePath(self):
        """Tests the feature can match old file with new file after file move."""
        feature = TouchCrashedFileMetaFeature(
            [TouchCrashedFileFeature()],
            options={'replace_path': {
                'old/dir': 'new/dir'
            }})

        self.assertTrue(
            feature.Match(
                CrashedFile('new/dir/a/file.cc'),
                FileChangeInfo(ChangeType.MODIFY, 'old/dir/a/file.cc',
                               'old/dir/a/file.cc')))
Пример #22
0
    def testMatchesTouchedFile(self):
        """Tests that ``MatchesTouchedFile`` matches touched files correctly."""
        touched_file = FileChangeInfo(ChangeType.MODIFY, 'a/b.h', 'a/b.h')
        self.assertFalse(
            self.chromium_project.MatchesTouchedFile(
                'dummy', touched_file.changed_path))
        self.assertTrue(
            self.chromium_project.MatchesTouchedFile(
                'src/', touched_file.changed_path))

        deleted_file = FileChangeInfo(ChangeType.DELETE, 'a/b.h', None)
        self.assertTrue(
            self.chromium_project.MatchesTouchedFile(
                'src/', deleted_file.changed_path))
        self.assertFalse(
            self.android_project.MatchesTouchedFile('src/',
                                                    deleted_file.changed_path))

        add_file = FileChangeInfo(ChangeType.ADD, None,
                                  'googleplex-android/b.java')
        self.assertTrue(
            self.android_project.MatchesTouchedFile('android_path/',
                                                    add_file.changed_path))
 def testFeatureValueIsZeroWhenAFileIsDeleted(self):
     """Tests that the feature returns 0 when a file is deleted."""
     changelog = self.GetDummyChangeLog()._replace(
         # File deleted in the same directory:
         touched_files=[
             FileChangeInfo.FromDict({
                 'change_type': 'delete',
                 'new_path': None,
                 'old_path': 'p/a.cc',
             })
         ])
     suspect = Suspect(changelog, 'src/')
     feature_value = self._feature(self._report)(suspect)
     self.assertEqual(0.0, feature_value.value)
    def testFilePathMatchAfterChangeFileExtension(self):
        """Tests feature can match old file with new file after extension change."""
        feature = TouchCrashedFileMetaFeature(
            [TouchCrashedFileFeature()],
            options={'change_file_extension': {
                'dir/a': {
                    'cpp': 'cc'
                }
            }})

        self.assertTrue(
            feature.Match(
                CrashedFile('dir/a/file_name.cc'),
                FileChangeInfo(ChangeType.MODIFY, 'dir/a/file_name.cpp',
                               'dir/a/file_name.cpp')))
    def testFilePathMatchAfterChangeNamingConvention(self):
        """Tests the feature can match old file with new file after file name."""
        feature = TouchCrashedFileMetaFeature([TouchCrashedFileFeature()],
                                              options={
                                                  'change_naming_convention': {
                                                      'dir/a':
                                                      'capital_to_underscore'
                                                  }
                                              })

        self.assertTrue(
            feature.Match(
                CrashedFile('dir/a/file_name.cc'),
                FileChangeInfo(ChangeType.MODIFY, 'dir/a/FileName.cc',
                               'dir/a/FileName.cc')))
Пример #26
0
    def testReplacePath(self):
        """Tests feature can still match components with files after file move."""
        components = [Component('new_comp', ['src/dep/b/new_dir'], '', 'team')]
        # Only construct the classifier once, rather than making a new one every
        # time we call a method on it.
        classifier = ComponentClassifier(components, 3, _MOCK_REPO_TO_DEP_PATH)
        feature = TouchCrashedComponentFeature(
            classifier, options={'replace_path': {
                'a/old_dir': 'b/new_dir'
            }})

        match_func = feature.GetMatchFunction('src/dep')
        self.assertTrue(
            match_func(
                CrashedComponent('new_comp'),
                FileChangeInfo(ChangeType.MODIFY, 'a/old_dir/f.cc',
                               'a/old_dir/f.cc')))
Пример #27
0
    def testGetChangedLinesNoneBlame(self):
        repo_info = {
            'repo_url': 'https://chromium.googlesource.com/chromium/src.git',
            'revision': '10'
        }
        touched_file = FileChangeInfo.FromDict({
            'change_type': ChangeType.MODIFY,
            'old_path': 'a/b/c.cc',
            'new_path': 'a/b/c.cc'
        })
        line_numbers = [2, 7, 8]
        commit_revision = '7'
        self.mock(CachedGitilesRepository, 'GetBlame', self._MockGetBlame)
        changed_line_numbers = (
            build_failure_analysis._GetChangedLinesForChromiumRepo(
                repo_info, touched_file, line_numbers, commit_revision))

        self.assertEqual([], changed_line_numbers)
 def testFeatureValueIsOneWhenThereIsMatchedDirectory(self):
     """Test that feature value is 1 when there is matched directory."""
     frame1 = StackFrame(0, 'src/', 'func', 'p/f.cc', 'src/p/f.cc', [2, 3],
                         'h://repo')
     stack = CallStack(0, frame_list=[frame1])
     stack_trace = Stacktrace([stack], stack)
     deps = {'src/': Dependency('src/', 'h://repo', '8')}
     dep_rolls = {'src/': DependencyRoll('src/', 'h://repo', '2', '6')}
     report = CrashReport('8', 'sig', 'linux', stack_trace, ('2', '6'),
                          deps, dep_rolls)
     changelog = self.GetDummyChangeLog()._replace(touched_files=[
         FileChangeInfo.FromDict({
             'change_type': 'add',
             'new_path': 'p/a.cc',
             'old_path': None,
         })
     ])
     suspect = Suspect(changelog, 'src/')
     feature_value = self._feature(report)(suspect)
     self.assertEqual(1.0, feature_value.value)
Пример #29
0
    def _ParseChangeLogFromLogData(self, data):
        change_info = commit_util.ExtractChangeInfo(data['message'], self._ref)

        touched_files = []
        for file_diff in data['tree_diff']:
            change_type = file_diff['type'].lower()
            if not diff.IsKnownChangeType(change_type):
                raise Exception('Unknown change type "%s"' % change_type)
            touched_files.append(
                FileChangeInfo(change_type, file_diff['old_path'],
                               file_diff['new_path']))

        reverted_revision = commit_util.GetRevertedRevision(data['message'])
        url = '%s/+/%s' % (self.repo_url, data['commit'])

        return ChangeLog(self._ContributorFromDict(data['author']),
                         self._ContributorFromDict(data['committer']),
                         data['commit'], change_info.get('commit_position'),
                         data['message'], touched_files, url,
                         change_info.get('code_review_url'), reverted_revision,
                         change_info.get('host'), change_info.get('change_id'))
Пример #30
0
def ChangeLogFromDict(data):
    touched_files = [
        FileChangeInfo.FromDict(touched_file)
        for touched_file in data.get('touched_files', [])
    ]

    author = Contributor(
        data.get('author', {}).get('name', 'author'),
        data.get('author', {}).get('email', 'email'),
        data.get('author', {}).get('time', 'time'))
    committer = Contributor(
        data.get('committer', {}).get('name', 'committer'),
        data.get('committer', {}).get('email', 'email'),
        data.get('committer', {}).get('time', 'time'))
    return ChangeLog(author, committer, data.get('revision'),
                     data.get('commit_position'), data.get('message'),
                     touched_files, data.get('commit_url'),
                     data.get('code_review_url'),
                     data.get('reverted_revision'),
                     data.get('review_server_host'),
                     data.get('review_change_id'))