Пример #1
0
    def testUpdateGroup_InvalidRange_PropertiesAreUpdated(self):
        anomalies = self._AddAnomalies()

        # Add another anomaly to the same group as the first two anomalies
        # by setting its bug ID to match that of an existing group.
        new_anomaly = anomaly.Anomaly(start_revision=3000,
                                      end_revision=4000,
                                      group=anomalies[0].group)
        new_anomaly_key = new_anomaly.put()

        # Change the anomaly revision to invalid range.
        alert_group.ModifyAlertsAndAssociatedGroups([new_anomaly],
                                                    start_revision=10,
                                                    end_revision=20)

        # After adding this new anomaly, it belongs to the group, and the group
        # no longer has a minimum revision range.
        group = anomalies[0].group.get()
        self.assertEqual(anomalies[0].group, new_anomaly_key.get().group)
        self.assertIsNone(group.start_revision)
        self.assertIsNone(group.end_revision)

        # Remove the new anomaly from the group by marking it invalid.
        alert_group.ModifyAlertsAndAssociatedGroups([new_anomaly_key.get()],
                                                    bug_id=-1)

        # Now, the anomaly group's revision range is valid again.
        group = anomalies[0].group.get()
        self.assertEqual(3000, group.start_revision)
        self.assertEqual(4000, group.end_revision)
Пример #2
0
    def testUpdateAnomalyGroup_BugIDUntriaged_GroupIsNone(self):
        anomalies = self._AddAnomalies()
        group2_key = anomalies[2].group

        # First give that group an actual bug_id
        alert_group.ModifyAlertsAndAssociatedGroups(anomalies[2:],
                                                    bug_id=11111)

        self.assertEqual(11111, group2_key.get().bug_id)

        # Now un-triage the bug, since it's the onyl one in the group the group's
        # bug_id should also be None
        alert_group.ModifyAlertsAndAssociatedGroups(anomalies[2:], bug_id=None)

        # Both groups should have been deleted
        self.assertIsNone(group2_key.get().bug_id)
Пример #3
0
    def testUpdateAnomalyGroup_BugIDInvalid_GroupDeleted(self):
        anomalies = self._AddAnomalies()
        group1_key = anomalies[0].group
        group2_key = anomalies[2].group

        alert_group.ModifyAlertsAndAssociatedGroups(anomalies, bug_id=-1)

        # Both groups should have been deleted
        self.assertIsNone(group1_key.get())
        self.assertIsNone(group2_key.get())
Пример #4
0
    def testUpdateAnomalyGroup_BugIDValid_GroupUpdated(self):
        anomalies = self._AddAnomalies()
        group1_key = anomalies[0].group
        group2_key = anomalies[2].group

        alert_group.ModifyAlertsAndAssociatedGroups(anomalies, bug_id=11111)

        # Both groups should have their bug_id's updated
        self.assertEqual(11111, group1_key.get().bug_id)
        self.assertEqual(11111, group2_key.get().bug_id)
Пример #5
0
def _MapAnomaliesToMergeIntoBug(dest_bug_id, source_bug_id):
    """Maps anomalies from source bug to destination bug.

  Args:
    dest_bug_id: Merge into bug (base bug) number.
    source_bug_id: The bug to be merged.
  """
    query = anomaly.Anomaly.query(anomaly.Anomaly.bug_id == int(source_bug_id))
    anomalies = query.fetch()

    alert_group.ModifyAlertsAndAssociatedGroups(anomalies,
                                                bug_id=int(dest_bug_id))
Пример #6
0
    def testUpdateAnomalyGroup_BugIDUntriaged_GroupRetainsBugID(self):
        anomalies = self._AddAnomalies()
        group1_key = anomalies[0].group

        # Groups aren't assigned a bug_id until after an alert is placed in the
        # group with a bug_id.
        group = group1_key.get()
        group.bug_id = 12345
        group.put()

        alert_group.ModifyAlertsAndAssociatedGroups(anomalies[:1], bug_id=None)

        self.assertEqual(12345, group1_key.get().bug_id)
Пример #7
0
    def testMarkAnomalyInvalid_AnomalyIsRemovedFromGroup(self):
        anomalies = self._AddAnomalies()

        # At first, two anomalies are in the same group.
        self.assertEqual(anomalies[0].group, anomalies[1].group)

        # Mark one of the alerts as invalid.
        self.assertEqual(12345, anomalies[1].bug_id)

        alert_group.ModifyAlertsAndAssociatedGroups([anomalies[1]], bug_id=-1)

        # Now, the alert marked as invalid has no group.
        # Also, the group's revision range has been updated accordingly.
        self.assertNotEqual(anomalies[0].group, anomalies[1].group)
        self.assertIsNone(anomalies[1].group)
        group = anomalies[0].group.get()
        self.assertEqual(2000, group.start_revision)
        self.assertEqual(4000, group.end_revision)
Пример #8
0
    def testUpdateAnomalyRevisionRange_UpdatesGroupRevisionRange(self):
        anomalies = self._AddAnomalies()

        # Add another anomaly to the same group as the first two anomalies,
        # but with a non-overlapping revision range.
        new_anomaly = anomaly.Anomaly(start_revision=3000,
                                      end_revision=4000,
                                      group=anomalies[0].group)
        new_anomaly.put()

        # Associate it with a group; alert_group.ModifyAlertsAndAssociatedGroups
        # will update the group's revision range here.
        alert_group.ModifyAlertsAndAssociatedGroups([new_anomaly],
                                                    start_revision=3010,
                                                    end_revision=3020)

        # Now the group's revision range is updated.
        group = anomalies[0].group.get()
        self.assertEqual(3010, group.start_revision)
        self.assertEqual(3020, group.end_revision)
Пример #9
0
    def _AssociateAlertsWithBug(self, bug_id, urlsafe_keys, is_confirmed):
        """Sets the bug ID for a set of alerts.

    This is done after the user enters and submits a bug ID.

    Args:
      bug_id: Bug ID number, as a string.
      urlsafe_keys: Comma-separated Alert keys in urlsafe format.
      is_confirmed: Whether the user has confirmed that they really want
          to associate the alerts with a bug even if it appears that the
          revision ranges don't overlap.
    """
        # Validate bug ID.
        try:
            bug_id = int(bug_id)
        except ValueError:
            self.RenderHtml('bug_result.html',
                            {'error': 'Invalid bug ID "%s".' % str(bug_id)})
            return

        # Get Anomaly entities and related TestMetadata entities.
        alert_keys = [ndb.Key(urlsafe=k) for k in urlsafe_keys.split(',')]
        alert_entities = ndb.get_multi(alert_keys)

        if not is_confirmed:
            warning_msg = self._VerifyAnomaliesOverlap(alert_entities, bug_id)
            if warning_msg:
                self._ShowConfirmDialog('associate_alerts', warning_msg, {
                    'bug_id': bug_id,
                    'keys': urlsafe_keys,
                })
                return

        alert_group.ModifyAlertsAndAssociatedGroups(alert_entities,
                                                    bug_id=bug_id)

        self.RenderHtml('bug_result.html', {'bug_id': bug_id})
Пример #10
0
    def _CreateBug(self, summary, description, labels, components,
                   urlsafe_keys):
        """Creates a bug, associates it with the alerts, sends a HTML response.

    Args:
      summary: The new bug summary string.
      description: The new bug description string.
      labels: List of label strings for the new bug.
      components: List of component strings for the new bug.
      urlsafe_keys: Comma-separated alert keys in urlsafe format.
    """
        # Only project members (@chromium.org accounts) can be owners of bugs.
        owner = self.request.get('owner')
        if owner and not owner.endswith('@chromium.org'):
            self.RenderHtml(
                'bug_result.html',
                {'error': 'Owner email address must end with @chromium.org.'})
            return

        alert_keys = [ndb.Key(urlsafe=k) for k in urlsafe_keys.split(',')]
        alerts = ndb.get_multi(alert_keys)

        if not description:
            description = 'See the link to graphs below.'

        milestone_label = _MilestoneLabel(alerts)
        if milestone_label:
            labels.append(milestone_label)

        cc = self.request.get('cc')

        http = oauth2_decorator.DECORATOR.http()
        user_issue_tracker_service = issue_tracker_service.IssueTrackerService(
            http)

        new_bug_response = user_issue_tracker_service.NewBug(
            summary,
            description,
            labels=labels,
            components=components,
            owner=owner,
            cc=cc)
        if 'error' in new_bug_response:
            self.RenderHtml('bug_result.html',
                            {'error': new_bug_response['error']})
            return

        bug_id = new_bug_response['bug_id']
        bug_data.Bug(id=bug_id).put()

        alert_group.ModifyAlertsAndAssociatedGroups(alerts, bug_id=bug_id)

        comment_body = _AdditionalDetails(bug_id, alerts)
        # Add the bug comment with the service account, so that there are no
        # permissions issues.
        dashboard_issue_tracker_service = issue_tracker_service.IssueTrackerService(
            utils.ServiceAccountHttp())
        dashboard_issue_tracker_service.AddBugComment(bug_id, comment_body)

        template_params = {'bug_id': bug_id}
        if all(k.kind() == 'Anomaly' for k in alert_keys):
            logging.info('Kicking bisect for bug ' + str(bug_id))
            bisect_result = auto_bisect.StartNewBisectForBug(bug_id)
            if 'error' in bisect_result:
                logging.info('Failed to kick bisect for ' + str(bug_id))
                template_params['bisect_error'] = bisect_result['error']
            else:
                logging.info('Successfully kicked bisect for ' + str(bug_id))
                template_params.update(bisect_result)
        else:
            kinds = set()
            for k in alert_keys:
                kinds.add(k.kind())
            logging.info(
                'Didn\'t kick bisect for bug id %s because alerts had kinds %s',
                bug_id, list(kinds))

        self.RenderHtml('bug_result.html', template_params)