com.epam.ta.reportportal.events.handler.LaunchFinishedEventHandler.java Source code

Java tutorial

Introduction

Here is the source code for com.epam.ta.reportportal.events.handler.LaunchFinishedEventHandler.java

Source

/*
 * Copyright 2016 EPAM Systems
 *
 *
 * This file is part of EPAM Report Portal.
 * https://github.com/reportportal/service-api
 *
 * Report Portal is free software: you can redistribute it and/or modify
 * it under the terms of the GNU General Public License as published by
 * the Free Software Foundation, either version 3 of the License, or
 * (at your option) any later version.
 *
 * Report Portal is distributed in the hope that it will be useful,
 * but WITHOUT ANY WARRANTY; without even the implied warranty of
 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
 * GNU General Public License for more details.
 *
 * You should have received a copy of the GNU General Public License
 * along with Report Portal.  If not, see <http://www.gnu.org/licenses/>.
 */
package com.epam.ta.reportportal.events.handler;

import com.epam.ta.reportportal.commons.SendCase;
import com.epam.ta.reportportal.database.dao.FailReferenceResourceRepository;
import com.epam.ta.reportportal.database.dao.LaunchRepository;
import com.epam.ta.reportportal.database.dao.TestItemRepository;
import com.epam.ta.reportportal.database.dao.UserRepository;
import com.epam.ta.reportportal.database.entity.Launch;
import com.epam.ta.reportportal.database.entity.Project;
import com.epam.ta.reportportal.database.entity.Status;
import com.epam.ta.reportportal.database.entity.item.FailReferenceResource;
import com.epam.ta.reportportal.database.entity.item.TestItem;
import com.epam.ta.reportportal.database.entity.project.ProjectUtils;
import com.epam.ta.reportportal.database.entity.user.User;
import com.epam.ta.reportportal.events.LaunchFinishedEvent;
import com.epam.ta.reportportal.util.analyzer.IIssuesAnalyzer;
import com.epam.ta.reportportal.util.email.EmailService;
import com.epam.ta.reportportal.util.email.MailServiceFactory;
import com.epam.ta.reportportal.ws.model.launch.Mode;
import com.epam.ta.reportportal.ws.model.project.email.EmailSenderCase;
import com.epam.ta.reportportal.ws.model.project.email.ProjectEmailConfig;
import com.google.common.annotations.VisibleForTesting;
import org.apache.commons.lang3.BooleanUtils;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.beans.factory.annotation.Value;
import org.springframework.context.event.EventListener;
import org.springframework.http.server.ServletServerHttpRequest;
import org.springframework.stereotype.Component;
import org.springframework.web.util.UriComponentsBuilder;

import javax.inject.Provider;
import javax.servlet.http.HttpServletRequest;
import java.util.List;
import java.util.Objects;
import java.util.Optional;
import java.util.stream.Collectors;

/**
 * @author Andrei Varabyeu
 */
@Component
public class LaunchFinishedEventHandler {

    private static final Logger LOGGER = LoggerFactory.getLogger(LaunchFinishedEventHandler.class);

    private final FailReferenceResourceRepository issuesRepository;

    private final TestItemRepository testItemRepository;

    private final LaunchRepository launchRepository;

    private final IIssuesAnalyzer analyzerService;

    private final MailServiceFactory emailServiceFactory;

    private final UserRepository userRepository;

    private final Provider<HttpServletRequest> currentRequest;

    private final Integer autoAnalysisDepth;

    @Autowired
    public LaunchFinishedEventHandler(IIssuesAnalyzer analyzerService, UserRepository userRepository,
            TestItemRepository testItemRepository, Provider<HttpServletRequest> currentRequest,
            LaunchRepository launchRepository, MailServiceFactory emailServiceFactory,
            FailReferenceResourceRepository issuesRepository,
            @Value("${rp.issue.analyzer.depth}") Integer autoAnalysisDepth) {
        this.analyzerService = analyzerService;
        this.userRepository = userRepository;
        this.testItemRepository = testItemRepository;
        this.currentRequest = currentRequest;
        this.launchRepository = launchRepository;
        this.emailServiceFactory = emailServiceFactory;
        this.issuesRepository = issuesRepository;
        this.autoAnalysisDepth = autoAnalysisDepth;
    }

    @EventListener
    public void onApplicationEvent(LaunchFinishedEvent event) {
        afterFinishLaunch(event.getProject(), event.getLaunch());
    }

    private void afterFinishLaunch(final Project project, final Launch launch) { // NOSONAR

        /* Should we send email right now or wait till AA is finished? */
        boolean waitForAutoAnalysis;

        /* Avoid NULL object processing */
        if (null == project || null == launch)
            return;

        Optional<EmailService> emailService = emailServiceFactory
                .getDefaultEmailService(project.getConfiguration().getEmailConfig());

        /* If AA enabled then waiting results processing */
        waitForAutoAnalysis = BooleanUtils.toBoolean(project.getConfiguration().getIsAutoAnalyzerEnabled());

        /* If email enabled and AA disabled then send results immediately */
        if (!waitForAutoAnalysis) {
            emailService.ifPresent(service -> sendEmailRightNow(launch, project, service));
        }

        // Do not process debug launches.
        if (launch.getMode().equals(Mode.DEBUG))
            return;
        List<FailReferenceResource> resources = issuesRepository.findAllLaunchIssues(launch.getId());
        if (!project.getConfiguration().getIsAutoAnalyzerEnabled()) {
            this.clearInvestigatedIssues(resources);
            return;
        }
        List<TestItem> previous = analyzerService.collectPreviousIssues(autoAnalysisDepth, launch.getId(),
                project.getName());
        List<TestItem> converted = resources.stream()
                .map(resource -> testItemRepository.findOne(resource.getTestItemRef()))
                .collect(Collectors.toList());
        analyzerService.analyze(launch.getId(), converted, previous);

        // Remove already processed items from repository
        this.clearInvestigatedIssues(resources);

        /* Previous email sending cycle was skipped due waiting AA results */
        if (waitForAutoAnalysis) {
            // Get launch with AA results
            Launch freshLaunch = launchRepository.findOne(launch.getId());
            emailService.ifPresent(it -> sendEmailRightNow(freshLaunch, project, it));
        }
    }

    /**
     * Clear failReferences repository
     *
     * @param issues List of references to be deleted
     */
    private void clearInvestigatedIssues(List<FailReferenceResource> issues) {
        issuesRepository.delete(issues);
    }

    /**
     * @param launch launch to be evaluated
     * @return success rate of provided launch in %
     */
    private static double getSuccessRate(Launch launch) {
        Double ti = launch.getStatistics().getIssueCounter().getToInvestigateTotal().doubleValue();
        Double pb = launch.getStatistics().getIssueCounter().getProductBugTotal().doubleValue();
        Double si = launch.getStatistics().getIssueCounter().getSystemIssueTotal().doubleValue();
        Double ab = launch.getStatistics().getIssueCounter().getAutomationBugTotal().doubleValue();
        Double total = launch.getStatistics().getExecutionCounter().getTotal().doubleValue();
        return total == 0 ? total : (ti + pb + si + ab) / total;
    }

    /**
     * @param launch Launch to be evaluated
     * @param option SendCase option
     * @return TRUE of success rate is enough for notification
     */
    static boolean isSuccessRateEnough(Launch launch, SendCase option) {
        switch (option) {
        case ALWAYS:
            return true;
        case FAILED:
            return launch.getStatus().equals(Status.FAILED);
        case TO_INVESTIGATE:
            return launch.getStatistics().getIssueCounter().getToInvestigateTotal() > 0;
        case MORE_10:
            return getSuccessRate(launch) > 0.1;
        case MORE_20:
            return getSuccessRate(launch) > 0.2;
        case MORE_50:
            return getSuccessRate(launch) > 0.5;
        default:
            return false;
        }
    }

    /**
     * Validate matching of finished launch name and project settings for
     * emailing
     *
     * @param launch  Launch to be evaluated
     * @param oneCase Mail case
     * @return TRUE if launch name matched
     */
    static boolean isLaunchNameMatched(Launch launch, EmailSenderCase oneCase) {
        List<String> configuredNames = oneCase.getLaunchNames();
        return (null == configuredNames) || (configuredNames.isEmpty())
                || configuredNames.contains(launch.getName());
    }

    /**
     * Validate matching of finished launch tags and project settings for
     * emailing
     *
     * @param launch  Launch to be evaluated
     * @param oneCase Mail case
     * @return TRUE if tags matched
     */
    @VisibleForTesting
    static boolean isTagsMatched(Launch launch, EmailSenderCase oneCase) {
        return !(null != oneCase.getTags() && !oneCase.getTags().isEmpty())
                || null != launch.getTags() && launch.getTags().containsAll(oneCase.getTags());
    }

    /**
     * Try to send email when it is needed
     *
     * @param launch       Launch to be used
     * @param project      Project to be used
     * @param emailService Mail Service
     */
    void sendEmailRightNow(Launch launch, Project project, EmailService emailService) {
        ProjectEmailConfig projectConfig = project.getConfiguration().getEmailConfig();
        for (EmailSenderCase one : projectConfig.getEmailCases()) {
            Optional<SendCase> option = SendCase.findByName(one.getSendCase());
            boolean successRate = isSuccessRateEnough(launch, option.get());
            boolean matchedNames = isLaunchNameMatched(launch, one);
            boolean matchedTags = isTagsMatched(launch, one);
            List<String> recipients = one.getRecipients();
            if (successRate && matchedNames && matchedTags) {
                String[] recipientsArray = findRecipients(launch.getUserRef(), recipients);
                try {
                    /* Update with static Util resources provider */
                    String basicURL = UriComponentsBuilder
                            .fromHttpRequest(new ServletServerHttpRequest(currentRequest.get()))
                            .replacePath(String.format("/#%s/launches/all/", project.getName())).build()
                            .toUriString();

                    emailService.sendLaunchFinishNotification(recipientsArray, basicURL + launch.getId(), launch,
                            project.getConfiguration());
                } catch (Exception e) {
                    LOGGER.error("Unable to send email. Error: \n{}", e);
                }
            }
        }
    }

    String[] findRecipients(String owner, List<String> recipients) {
        return recipients.stream().map(recipient -> {
            if (recipient.contains("@")) {
                return recipient;
            } else {
                String toFind = recipient.equals(ProjectUtils.getOwner()) ? owner : recipient;
                User user = userRepository.findOne(toFind);
                if (user != null) {
                    return user.getEmail();
                }
                return null;
            }
        }).filter(Objects::nonNull).distinct().toArray(String[]::new);
    }

}