예제 #1
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)
예제 #2
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)
예제 #3
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)
예제 #4
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)])])
예제 #5
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)
예제 #6
0
 def testMatchSuspectWithFrameInfos(self):
     """Tests ``MatchSuspectWithFrameInfos`` function."""
     frame1 = StackFrame(0, 'src/', 'func', 'f.cc', 'src/f.cc', [2, 3],
                         'h://repo')
     frame2 = StackFrame(1, 'src/', 'func', 'a.cc', 'src/a.cc', [31, 32],
                         'h://repo')
     grouped_frame_infos = {
         MockCrashedGroup('src/f.cc'): [FrameInfo(frame1, 0)],
         MockCrashedGroup('src/a.cc'): [FrameInfo(frame2, 0)]
     }
     suspect = Suspect(_CHANGELOG, 'src/')
     matches = crash_util.MatchSuspectWithFrameInfos(
         suspect, grouped_frame_infos, Match)
     crashed = MockCrashedGroup('src/a.cc')
     expected_matches = {
         crashed:
         CrashMatch(crashed, _CHANGELOG.touched_files,
                    [FrameInfo(frame2, 0)])
     }
     self.assertDictEqual(matches, expected_matches)
예제 #7
0
    def testFilePathIdfFeatureCallForMatches(self):
        """Tests ``__call__`` of ``FilePathIdfFeature`` for non-empty matches."""
        report = CrashReport(None, None, None, None, None, None, None)
        frame1 = StackFrame(0, '', 'func', 'keyword1', 'src/keyword1', [2],
                            'http://repo')
        frame2 = StackFrame(0, '', 'func', 'keyword2', 'src/keyword2', [9],
                            'http://repo')
        matches = {
            CrashedFile('keyword1'):
            CrashMatch(CrashedFile('keyword1'), ['keyword1'],
                       [FrameInfo(frame1, 0)]),
            CrashedFile('keyword2'):
            CrashMatch(CrashedFile('keyword2'), ['keyword2'],
                       [FrameInfo(frame2, 0)])
        }

        feature_value = self.feature(report)(None, matches)
        self.assertEqual(
            feature_value.value,
            file_path_idf.LogRegressNomalize(math.log(9 / float(1 + 3))))
예제 #8
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)
예제 #9
0
    def testIndexFramesWithCrashedGroup(self):
        """Tests ``IndexFramesWithCrashedGroup`` function."""
        frame1 = StackFrame(0, 'src/', 'func', 'f.cc', 'src/f.cc', [2, 3],
                            'h://repo')
        frame2 = StackFrame(1, 'src/', 'func', 'a.cc', 'src/a.cc', [31, 32],
                            'h://repo')
        frame3 = StackFrame(1, 'src/dummy', 'func', 'a.cc', 'src/dummy/a.cc',
                            [131, 132], 'h://repo')
        stack = CallStack(0, frame_list=[frame1, frame2, frame3])
        stack_trace = Stacktrace([stack], stack)
        deps = {'src/': Dependency('src/', 'h://repo', 'rev3')}

        indexed_frame_infos = crash_util.IndexFramesWithCrashedGroup(
            stack_trace, Factory, deps)
        expected_frame_infos = {
            'src/': {
                MockCrashedGroup('src/f.cc'): [FrameInfo(frame1, 0)],
                MockCrashedGroup('src/a.cc'): [FrameInfo(frame2, 0)]
            }
        }
        self.assertEqual(indexed_frame_infos, expected_frame_infos)
예제 #10
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)
예제 #11
0
def IndexFramesWithCrashedGroup(stacktrace, crashed_group_factory,
                                dependencies):
  """Index frames in stacktrace by dep_path and crashed_groups.

  Args:
    stacktrace (Stacktrace): The stacktrace to parse.
    crashed_group_factory (callable): A callable to factory crashed_group.
      N.B. So as to be used a key in a dict, the ``crashed_group`` should be
      able to be hashed.
    dependencies (dict of Dependency): Dict mapping dep path to ``Dependency``s.
      The ``dependencies`` is used to filter those frames whose dep path are
      not in ``dependencies``.

  Returns:
    A dict mapping dep_path to crashed_group to list of ``FrameInfo``s.
    For example:
    {
        'src/': {
            'a.cc': [
                FrameInfo(StackFrame(0, 'src/', '', 'func', 'a.cc', [1]), 0),
                FrameInfo(StackFrame(2, 'src/', '', 'func', 'a.cc', [33]), 0),
            ]
        }
    }
  """
  frame_infos = defaultdict(lambda: defaultdict(list))

  for stack in stacktrace.stacks:
    for frame in stack.frames:
      if frame.dep_path is None:
        continue

      if frame.dep_path not in dependencies:
        continue

      crashed_group = crashed_group_factory(frame)
      if crashed_group:
        frame_infos[frame.dep_path][crashed_group].append(
            FrameInfo(frame, stack.priority))

  return frame_infos
예제 #12
0
    def testIsLogOneWhenThereIsMatchedFiles(self):
        """Test that the feature returns log(1) when there is matched file."""
        report = self._GetDummyReport()
        suspect = self._GetMockSuspect()
        frame = StackFrame(index=0,
                           dep_path=suspect.dep_path,
                           function='func',
                           file_path='a.cc',
                           raw_file_path='a.cc',
                           crashed_line_numbers=[7])

        crashed = CrashedFile(frame)
        matches = {
            crashed:
            CrashMatch(crashed,
                       [FileChangeInfo(ChangeType.MODIFY, 'a.cc', 'a.cc')],
                       [FrameInfo(frame=frame, priority=0)])
        }
        self.assertEqual(
            1.0,
            TouchCrashedFileFeature()(report)(suspect, matches).value)
예제 #13
0
 def testTopFrameIndexValueForBottonFrame(self):
     """Test that feature returns 0 when the frame index is larger than max."""
     report = self._GetDummyReport()
     suspect = self._GetMockSuspect()
     frame = StackFrame(index=_MAXIMUM + 1,
                        dep_path=suspect.dep_path,
                        function='func',
                        file_path='a.cc',
                        raw_file_path='a.cc',
                        crashed_line_numbers=[7])
     crashed = CrashedFile(frame)
     matches = {
         crashed:
         CrashMatch(crashed,
                    [FileChangeInfo(ChangeType.MODIFY, 'a.cc', 'a.cc')],
                    [FrameInfo(frame=frame, priority=0)])
     }
     self.assertEqual(
         0.0,
         top_frame_index.TopFrameIndexFeature(_MAXIMUM)(report)(
             suspect, matches).value)
예제 #14
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')
        profiler_frame = ProfilerStackFrame(0,
                                            -0.1,
                                            -5.3,
                                            True,
                                            function_start_line=13)
        profiler_frame_without_line_number = ProfilerStackFrame(
            0, -0.1, -5.3, True, function_start_line=None)
        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)

            # Test with a ProfilerStackFrame
            distance_info = feature.DistanceBetweenTouchedFileAndFrameInfos(
                'rev', touched_file, [
                    FrameInfo(profiler_frame, 0),
                    FrameInfo(profiler_frame_without_line_number, 0)
                ], Dependency('src/', 'https://repo', 'rev'))
            self.assertEqual(distance_info,
                             min_distance.Distance(4, profiler_frame))

            # Test that the distance remains at ``inf`` if the ProfilerStackFrames
            # passed in do not have line numbers.
            distance_info = feature.DistanceBetweenTouchedFileAndFrameInfos(
                'rev', touched_file,
                [FrameInfo(profiler_frame_without_line_number, 0)],
                Dependency('src/', 'https://repo', 'rev'))
            self.assertEqual(distance_info,
                             min_distance.Distance(float('inf'), None))