Beispiel #1
0
    def _update(self, data, user, many=True):
        ids = []
        error_line_ids = set()
        classification_ids = set()
        bug_number_classifications = {}

        for item in data:
            line_id = item.get("id")
            if line_id is None:
                return "No text log error id provided", HTTP_400_BAD_REQUEST
            try:
                line_id = int(line_id)
            except ValueError:
                return "Text log error id was not an integer", HTTP_400_BAD_REQUEST

            error_line_ids.add(line_id)

            classification_id = item.get("best_classification")

            if classification_id is not None:
                classification_ids.add(classification_id)

            bug_number = item.get("bug_number")

            if (not classification_id and
                bug_number is not None and
                bug_number not in bug_number_classifications):
                bug_number_classifications[bug_number], _ = (
                    ClassifiedFailure.objects.get_or_create(bug_number=bug_number))

            ids.append((line_id, classification_id, bug_number))

        error_lines = as_dict(
            TextLogError.objects
            .prefetch_related('classified_failures')
            .filter(id__in=error_line_ids), "id")

        if len(error_lines) != len(error_line_ids):
            missing = error_line_ids - set(error_lines.keys())
            return ("No text log error with id: {0}".format(", ".join(missing)),
                    HTTP_404_NOT_FOUND)

        classifications = as_dict(
            ClassifiedFailure.objects.filter(id__in=classification_ids), "id")

        if len(classifications) != len(classification_ids):
            missing = classification_ids - set(classifications.keys())
            return ("No classification with id: {0}".format(", ".join(missing)),
                    HTTP_404_NOT_FOUND)

        for line_id, classification_id, bug_number in ids:
            logger.debug("line_id: %s, classification_id: %s, bug_number: %s" %
                         (line_id, classification_id, bug_number))
            error_line = error_lines[line_id]
            if classification_id is not None:
                logger.debug("Using classification id")
                classification = classifications[classification_id]
                if bug_number is not None and bug_number != classification.bug_number:
                    logger.debug("Updating classification bug number")
                    classification = classification.set_bug(bug_number)
            elif bug_number is not None:
                logger.debug("Using bug number")
                classification = bug_number_classifications[bug_number]
            else:
                logger.debug("Using null classification")
                classification = None

            error_line.mark_best_classification_verified(classification)
            error_line.step.job.update_after_verification(user)

        # Force failure line to be reloaded, including .classified_failures
        rv = (TextLogError.objects
              .prefetch_related('classified_failures')
              .filter(id__in=error_line_ids))

        if not many:
            rv = rv[0]

        return (serializers.TextLogErrorSerializer(rv, many=many).data,
                HTTP_200_OK)
    def _update(self, data, user, many=True):
        ids = []
        error_line_ids = set()
        classification_ids = set()
        bug_number_classifications = {}

        for item in data:
            line_id = item.get("id")
            if line_id is None:
                return "No text log error id provided", HTTP_400_BAD_REQUEST
            try:
                line_id = int(line_id)
            except ValueError:
                return "Text log error id was not an integer", HTTP_400_BAD_REQUEST

            error_line_ids.add(line_id)

            classification_id = item.get("best_classification")

            if classification_id is not None:
                classification_ids.add(classification_id)

            bug_number = item.get("bug_number")

            if (not classification_id and
                bug_number is not None and
                bug_number not in bug_number_classifications):
                bug_number_classifications[bug_number], _ = (
                    ClassifiedFailure.objects.get_or_create(bug_number=bug_number))

            ids.append((line_id, classification_id, bug_number))

        error_lines = as_dict(
            TextLogError.objects
            .prefetch_related('classified_failures')
            .filter(id__in=error_line_ids), "id")

        if len(error_lines) != len(error_line_ids):
            missing = error_line_ids - set(error_lines.keys())
            return ("No text log error with id: {0}".format(", ".join(missing)),
                    HTTP_404_NOT_FOUND)

        classifications = as_dict(
            ClassifiedFailure.objects.filter(id__in=classification_ids), "id")

        if len(classifications) != len(classification_ids):
            missing = classification_ids - set(classifications.keys())
            return ("No classification with id: {0}".format(", ".join(missing)),
                    HTTP_404_NOT_FOUND)

        jobs = set()
        for line_id, classification_id, bug_number in ids:
            logger.debug("line_id: %s, classification_id: %s, bug_number: %s",
                         line_id, classification_id, bug_number)
            error_line = error_lines[line_id]
            if classification_id is not None:
                logger.debug("Using classification id")
                classification = classifications[classification_id]
                if bug_number is not None and bug_number != classification.bug_number:
                    logger.debug("Updating classification bug number")
                    classification = classification.set_bug(bug_number)
            elif bug_number is not None:
                logger.debug("Using bug number")
                classification = bug_number_classifications[bug_number]
            else:
                logger.debug("Using null classification")
                classification = None

            jobs.add(error_line.step.job)
            error_line.mark_best_classification_verified(classification)

        for job in jobs:
            job.update_after_verification(user)

        # Force failure line to be reloaded, including .classified_failures
        rv = (TextLogError.objects
              .prefetch_related('classified_failures')
              .filter(id__in=error_line_ids))

        if not many:
            rv = rv[0]

        return (serializers.TextLogErrorSerializer(rv, many=many).data,
                HTTP_200_OK)
    def _update(self, data, many=False):
        bug_numbers = {}

        for item in data:
            classified_failure_id = int(item.get("id"))
            if classified_failure_id is None:
                return "No id provided", 400

            bug_number = item.get('bug_number')
            if bug_number is None:
                return "No bug number provided", 400

            bug_numbers[classified_failure_id] = int(bug_number)

        classified_failures = as_dict(
            ClassifiedFailure.objects.filter(id__in=bug_numbers.keys()), "id")

        if len(classified_failures) != len(bug_numbers):
            missing = set(bug_numbers.keys()) - set(classified_failures.keys())
            return "No classified failures with id: {0}".format(", ".join(missing)), 404

        merges = {}
        existing = ClassifiedFailure.objects.filter(bug_number__in=bug_numbers.values()).all()
        # Look for other classified failures with the same bug as one being updated, since
        # we don't want duplicate bugs
        existing = [item for item in existing
                    if item.id not in bug_numbers or item.bug_number != bug_numbers[item.id]]

        if existing:
            if any(item.id in bug_numbers for item in existing):
                return "Cannot swap classified failure bug numbers in a single operation", 400

            classified_failures.update(as_dict(existing, "id"))

            bug_to_classified_failure = defaultdict(list)
            for id, bug in bug_numbers.iteritems():
                bug_to_classified_failure[bug].append(classified_failures[id])
            # Merge the ClassifiedFailure being updated into the existing ClassifiedFailure
            # with the same bug number
            for retain in existing:
                for remove in bug_to_classified_failure[retain.bug_number]:
                    removed_id = remove.id
                    remove.replace_with(retain)
                    merges[removed_id] = retain

        # Ensure that the return value is ordered in the same way as the request
        rv = []
        for item in data:
            classification_id = int(item.get("id"))
            bug_number = bug_numbers[classification_id]
            if classification_id in merges:
                classification = merges[classification_id]
            else:
                classification = classified_failures[int(item.get("id"))]
                classification.bug_number = bug_number
                classification.save()
            rv.append(classification)

        if not many:
            rv = rv[0]

        return self.serializer_class(rv, many=many).data, 200
    def _update(self, data, many=False):
        bug_numbers = {}

        for item in data:
            classified_failure_id = int(item.get("id"))
            if classified_failure_id is None:
                return "No id provided", HTTP_400_BAD_REQUEST

            bug_number = item.get('bug_number')
            if bug_number is None:
                return "No bug number provided", HTTP_400_BAD_REQUEST

            bug_numbers[classified_failure_id] = int(bug_number)

        classified_failures = as_dict(
            ClassifiedFailure.objects.filter(id__in=bug_numbers.keys()), "id")

        existing = (ClassifiedFailure.objects
                    .filter(bug_number__in=bug_numbers.values())
                    .all())
        # Look for other classified failures with the same bug as one being updated, since
        # we don't want duplicate bugs
        existing = as_dict((item for item in existing
                            if item.id not in bug_numbers or
                            item.bug_number != bug_numbers[item.id]), "bug_number")

        # We don't count classified failures as missing if there is an existing failure
        # with the same bug number, even if it has a different id. This is because classification
        # of other jobs may have caused the classified failure to have been deleted and replaced
        # by another, without updating all the ids in the client
        missing = set(bug_numbers.keys()) - set(classified_failures.keys())
        replacements = {}
        for missing_id in missing:
            if bug_numbers[missing_id] in existing:
                existing_cf = existing[bug_numbers[missing_id]]
                replacements[missing_id] = existing_cf

        missing -= set(replacements.keys())

        if missing:
            return ("No classified failures with id: {0}"
                    .format(", ".join(str(item) for item in missing)),
                    HTTP_404_NOT_FOUND)

        if any(item.id in bug_numbers for item in existing.values()):
            return ("Cannot swap classified failure bug numbers in a single operation",
                    HTTP_400_BAD_REQUEST)

        classified_failures.update(as_dict(existing.values(), "id"))

        for old_id, replacement in iteritems(replacements):
            bug_numbers[replacement.id] = replacement
            del bug_numbers[old_id]

        merges = {}
        if existing:
            bug_to_classified_failure = defaultdict(list)
            for id, bug_number in iteritems(bug_numbers):
                bug_to_classified_failure[bug_number].append(classified_failures[id])
            # Merge the ClassifiedFailure being updated into the existing ClassifiedFailure
            # with the same bug number
            for bug_number, retain in iteritems(existing):
                for remove in bug_to_classified_failure[bug_number]:
                    removed_id = remove.id
                    remove.replace_with(retain)
                    merges[removed_id] = retain

        # Ensure that the return value is ordered in the same way as the request
        rv = []
        for item in data:
            classification_id = int(item.get("id"))

            if classification_id in merges:
                classification = merges[classification_id]
            elif classification_id in replacements:
                classification = replacements[classification_id]
            else:
                bug_number = bug_numbers[classification_id]
                classification = classified_failures[classification_id].set_bug(bug_number)
            rv.append(classification)

        if not many:
            rv = rv[0]

        return self.serializer_class(rv, many=many).data, HTTP_200_OK
Beispiel #5
0
    def _update(self, data, user, many=True):
        by_project = defaultdict(list)

        ids = []
        failure_line_ids = set()
        classification_ids = set()

        for item in data:
            line_id = int(item.get("id"))
            if line_id is None:
                return "No failure line id provided", HTTP_400_BAD_REQUEST

            failure_line_ids.add(line_id)

            if "best_classification" not in item:
                return "No classification id provided", HTTP_400_BAD_REQUEST

            classification_id = item.get("best_classification")

            if classification_id is not None:
                classification_ids.add(classification_id)

            ids.append((line_id, classification_id))

        failure_lines = as_dict(
            FailureLine.objects.prefetch_related('classified_failures').filter(
                id__in=failure_line_ids), "id")

        if len(failure_lines) != len(failure_line_ids):
            missing = failure_line_ids - set(failure_lines.keys())
            return ("No failure line with id: {0}".format(", ".join(missing)),
                    HTTP_404_NOT_FOUND)

        classifications = as_dict(
            ClassifiedFailure.objects.filter(id__in=classification_ids), "id")

        if len(classifications) != len(classification_ids):
            missing = classification_ids - set(classifications.keys())
            return ("No classification with id: {0}".format(
                ", ".join(missing)), HTTP_404_NOT_FOUND)

        for line_id, classification_id in ids:
            failure_line = failure_lines[line_id]
            if classification_id is not None:
                classification = classifications[classification_id]
            else:
                classification = None

            by_project[failure_line.repository.name].append(
                failure_line.job_guid)

            failure_line.mark_best_classification_verified(classification)

        for project, job_guids in iteritems(by_project):
            for job in Job.objects.filter(guid__in=job_guids):
                job.update_after_verification(user)

        # Force failure line to be reloaded, including .classified_failures
        rv = FailureLine.objects.prefetch_related(
            'classified_failures').filter(id__in=failure_line_ids)

        if not many:
            rv = rv[0]

        return (serializers.FailureLineNoStackSerializer(rv, many=many).data,
                HTTP_200_OK)
Beispiel #6
0
    def _update(self, data, user, many=True):
        by_project = defaultdict(list)

        ids = []
        failure_line_ids = set()
        classification_ids = set()

        for item in data:
            line_id = int(item.get("id"))
            if line_id is None:
                return "No failure line id provided", HTTP_400_BAD_REQUEST

            failure_line_ids.add(line_id)

            if "best_classification" not in item:
                return "No classification id provided", HTTP_400_BAD_REQUEST

            classification_id = item.get("best_classification")

            if classification_id is not None:
                classification_ids.add(classification_id)

            ids.append((line_id, classification_id))

        failure_lines = as_dict(
            FailureLine.objects.prefetch_related('classified_failures').filter(
                id__in=failure_line_ids), "id")

        if len(failure_lines) != len(failure_line_ids):
            missing = failure_line_ids - set(failure_lines.keys())
            return ("No failure line with id: {0}".format(", ".join(missing)),
                    HTTP_404_NOT_FOUND)

        classifications = as_dict(
            ClassifiedFailure.objects.filter(id__in=classification_ids), "id")

        if len(classifications) != len(classification_ids):
            missing = classification_ids - set(classifications.keys())
            return ("No classification with id: {0}".format(", ".join(missing)),
                    HTTP_404_NOT_FOUND)

        for line_id, classification_id in ids:
            failure_line = failure_lines[line_id]
            if classification_id is not None:
                classification = classifications[classification_id]
            else:
                classification = None

            by_project[failure_line.repository.name].append(failure_line.job_guid)

            failure_line.mark_best_classification_verified(classification)

        for project, job_guids in by_project.iteritems():
            with JobsModel(project) as jm:
                jobs = jm.get_job_ids_by_guid(job_guids)
                for job in jobs.values():
                    jm.update_after_verification(job["id"], user)

        # Force failure line to be reloaded, including .classified_failures
        rv = FailureLine.objects.prefetch_related('classified_failures').filter(
            id__in=failure_line_ids)

        if not many:
            rv = rv[0]

        return (serializers.FailureLineNoStackSerializer(rv, many=many).data,
                HTTP_200_OK)
Beispiel #7
0
    def _update(self, data, many=False):
        bug_numbers = {}

        for item in data:
            classified_failure_id = int(item.get("id"))
            if classified_failure_id is None:
                return "No id provided", HTTP_400_BAD_REQUEST

            bug_number = item.get('bug_number')
            if bug_number is None:
                return "No bug number provided", HTTP_400_BAD_REQUEST

            bug_numbers[classified_failure_id] = int(bug_number)

        classified_failures = as_dict(
            ClassifiedFailure.objects.filter(id__in=bug_numbers.keys()), "id")

        existing = (ClassifiedFailure.objects.filter(
            bug_number__in=bug_numbers.values()).all())
        # Look for other classified failures with the same bug as one being updated, since
        # we don't want duplicate bugs
        existing = as_dict(
            (item for item in existing if item.id not in bug_numbers
             or item.bug_number != bug_numbers[item.id]), "bug_number")

        # We don't count classified failures as missing if there is an existing failure
        # with the same bug number, even if it has a different id. This is because classification
        # of other jobs may have caused the classified failure to have been deleted and replaced
        # by another, without updating all the ids in the client
        missing = set(bug_numbers.keys()) - set(classified_failures.keys())
        replacements = {}
        for missing_id in missing:
            if bug_numbers[missing_id] in existing:
                existing_cf = existing[bug_numbers[missing_id]]
                replacements[missing_id] = existing_cf

        missing -= set(replacements.keys())

        if missing:
            return ("No classified failures with id: {0}".format(", ".join(
                str(item) for item in missing)), HTTP_404_NOT_FOUND)

        if any(item.id in bug_numbers for item in existing.values()):
            return (
                "Cannot swap classified failure bug numbers in a single operation",
                HTTP_400_BAD_REQUEST)

        classified_failures.update(as_dict(existing.values(), "id"))

        for old_id, replacement in iteritems(replacements):
            bug_numbers[replacement.id] = replacement
            del bug_numbers[old_id]

        merges = {}
        if existing:
            bug_to_classified_failure = defaultdict(list)
            for id, bug_number in iteritems(bug_numbers):
                bug_to_classified_failure[bug_number].append(
                    classified_failures[id])
            # Merge the ClassifiedFailure being updated into the existing ClassifiedFailure
            # with the same bug number
            for bug_number, retain in iteritems(existing):
                for remove in bug_to_classified_failure[bug_number]:
                    removed_id = remove.id
                    remove.replace_with(retain)
                    merges[removed_id] = retain

        # Ensure that the return value is ordered in the same way as the request
        rv = []
        for item in data:
            classification_id = int(item.get("id"))

            if classification_id in merges:
                classification = merges[classification_id]
            elif classification_id in replacements:
                classification = replacements[classification_id]
            else:
                bug_number = bug_numbers[classification_id]
                classification = classified_failures[
                    classification_id].set_bug(bug_number)
            rv.append(classification)

        if not many:
            rv = rv[0]

        return self.serializer_class(rv, many=many).data, HTTP_200_OK
Beispiel #8
0
    def _update(self, data, email, many=True):
        by_project = defaultdict(list)

        ids = []
        failure_line_ids = set()
        classification_ids = set()

        for item in data:
            line_id = int(item.get("id"))
            if line_id is None:
                return "No failure line id provided", 400

            failure_line_ids.add(line_id)

            if "best_classification" not in item:
                return "No classification id provided", 400

            classification_id = item.get("best_classification")

            if classification_id is not None:
                classification_ids.add(classification_id)

            ids.append((line_id, classification_id))

        failure_lines = as_dict(
            FailureLine.objects.prefetch_related('classified_failures').filter(
                id__in=failure_line_ids), "id")

        if len(failure_lines) != len(failure_line_ids):
            missing = failure_line_ids - set(failure_lines.keys())
            return "No failure line with id: {0}".format(
                ", ".join(missing)), 404

        classifications = as_dict(
            ClassifiedFailure.objects.filter(id__in=classification_ids), "id")

        if len(classifications) != len(classification_ids):
            missing = classification_ids - set(classifications.keys())
            return "No classification with id: {0}".format(
                ", ".join(missing)), 404

        for line_id, classification_id in ids:
            failure_line = failure_lines[line_id]
            if classification_id is not None:
                classification = classifications[classification_id]
            else:
                classification = None

            by_project[failure_line.repository.name].append(
                failure_line.job_guid)

            failure_line.best_classification = classification
            failure_line.best_is_verified = True
            failure_line.save()

            if (classification is not None and classification
                    not in failure_line.classified_failures.all()):
                manual_detector = Matcher.objects.get(name="ManualDetector")
                match = FailureMatch(failure_line=failure_line,
                                     classified_failure=classification,
                                     matcher=manual_detector,
                                     score=1.0)
                match.save()

        for project, job_guids in by_project.iteritems():
            with JobsModel(project) as jm:
                jobs = jm.get_job_ids_by_guid(job_guids)
                for job in jobs.values():
                    jm.update_after_verification(job["id"], email)

        # Force failure line to be reloaded, including .classified_failures
        rv = FailureLine.objects.prefetch_related(
            'classified_failures').filter(id__in=failure_line_ids)

        if not many:
            rv = rv[0]

        return serializers.FailureLineNoStackSerializer(rv,
                                                        many=many).data, 200
    def _update(self, data, many=False):
        bug_numbers = {}

        for item in data:
            classified_failure_id = int(item.get("id"))
            if classified_failure_id is None:
                return "No id provided", 400

            bug_number = item.get('bug_number')
            if bug_number is None:
                return "No bug number provided", 400

            bug_numbers[classified_failure_id] = int(bug_number)

        classified_failures = as_dict(
            ClassifiedFailure.objects.filter(id__in=bug_numbers.keys()), "id")

        if len(classified_failures) != len(bug_numbers):
            missing = set(bug_numbers.keys()) - set(classified_failures.keys())
            return "No classified failures with id: {0}".format(
                ", ".join(missing)), 404

        merges = {}
        existing = ClassifiedFailure.objects.filter(
            bug_number__in=bug_numbers.values()).all()
        # Look for other classified failures with the same bug as one being updated, since
        # we don't want duplicate bugs
        existing = [
            item for item in existing if item.id not in bug_numbers
            or item.bug_number != bug_numbers[item.id]
        ]

        if existing:
            if any(item.id in bug_numbers for item in existing):
                return "Cannot swap classified failure bug numbers in a single operation", 400

            classified_failures.update(as_dict(existing, "id"))

            bug_to_classified_failure = defaultdict(list)
            for id, bug in bug_numbers.iteritems():
                bug_to_classified_failure[bug].append(classified_failures[id])
            # Merge the ClassifiedFailure being updated into the existing ClassifiedFailure
            # with the same bug number
            for retain in existing:
                for remove in bug_to_classified_failure[retain.bug_number]:
                    removed_id = remove.id
                    remove.replace_with(retain)
                    merges[removed_id] = retain

        # Ensure that the return value is ordered in the same way as the request
        rv = []
        for item in data:
            classification_id = int(item.get("id"))
            bug_number = bug_numbers[classification_id]
            if classification_id in merges:
                classification = merges[classification_id]
            else:
                classification = classified_failures[int(item.get("id"))]
                classification.bug_number = bug_number
                classification.save()
            rv.append(classification)

        if not many:
            rv = rv[0]

        return self.serializer_class(rv, many=many).data, 200
Beispiel #10
0
    def _update(self, data, email, many=True):
        by_project = defaultdict(list)

        ids = []
        failure_line_ids = set()
        classification_ids = set()

        for item in data:
            line_id = int(item.get("id"))
            if line_id is None:
                return "No failure line id provided", 400

            failure_line_ids.add(line_id)

            if "best_classification" not in item:
                return "No classification id provided", 400

            classification_id = item.get("best_classification")

            if classification_id is not None:
                classification_ids.add(classification_id)

            ids.append((line_id, classification_id))

        failure_lines = as_dict(
            FailureLine.objects.prefetch_related('classified_failures').filter(
                id__in=failure_line_ids), "id")

        if len(failure_lines) != len(failure_line_ids):
            missing = failure_line_ids - set(failure_lines.keys())
            return "No failure line with id: {0}".format(", ".join(missing)), 404

        classifications = as_dict(
            ClassifiedFailure.objects.filter(id__in=classification_ids), "id")

        if len(classifications) != len(classification_ids):
            missing = classification_ids - set(classifications.keys())
            return "No classification with id: {0}".format(", ".join(missing)), 404

        for line_id, classification_id in ids:
            failure_line = failure_lines[line_id]
            if classification_id is not None:
                classification = classifications[classification_id]
            else:
                classification = None

            by_project[failure_line.repository.name].append(failure_line.job_guid)

            failure_line.best_classification = classification
            failure_line.best_is_verified = True
            failure_line.save()

            if (classification is not None and
                classification not in failure_line.classified_failures.all()):
                manual_detector = Matcher.objects.get(name="ManualDetector")
                match = FailureMatch(failure_line=failure_line,
                                     classified_failure=classification,
                                     matcher=manual_detector,
                                     score=1.0)
                match.save()

        for project, job_guids in by_project.iteritems():
            with JobsModel(project) as jm:
                jobs = jm.get_job_ids_by_guid(job_guids)
                for job in jobs.values():
                    jm.update_after_verification(job["id"], email)

        # Force failure line to be reloaded, including .classified_failures
        rv = FailureLine.objects.prefetch_related('classified_failures').filter(
            id__in=failure_line_ids)

        if not many:
            rv = rv[0]

        return serializers.FailureLineNoStackSerializer(rv, many=many).data, 200