All Downloads are FREE. Search and download functionalities are using the official Maven repository.

com.consol.citrus.remote.plugin.RunTestMojo Maven / Gradle / Ivy

/*
 * Copyright 2006-2018 the original author or authors.
 *
 * Licensed under the Apache License, Version 2.0 (the "License");
 * you may not use this file except in compliance with the License.
 * You may obtain a copy of the License at
 *
 *     http://www.apache.org/licenses/LICENSE-2.0
 *
 * Unless required by applicable law or agreed to in writing, software
 * distributed under the License is distributed on an "AS IS" BASIS,
 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
 * See the License for the specific language governing permissions and
 * limitations under the License.
 */

package com.consol.citrus.remote.plugin;

import java.io.File;
import java.io.IOException;
import java.io.StringWriter;
import java.net.URLEncoder;
import java.util.Arrays;
import java.util.List;
import java.util.stream.Collectors;
import java.util.stream.Stream;

import com.consol.citrus.TestClass;
import com.consol.citrus.exceptions.CitrusRuntimeException;
import com.consol.citrus.main.TestRunConfiguration;
import com.consol.citrus.remote.model.RemoteResult;
import com.consol.citrus.remote.plugin.config.RunConfiguration;
import com.consol.citrus.report.HtmlReporter;
import com.consol.citrus.report.JUnitReporter;
import com.consol.citrus.report.OutputStreamReporter;
import com.consol.citrus.report.SummaryReporter;
import com.consol.citrus.report.TestResults;
import com.consol.citrus.util.FileUtils;
import com.fasterxml.jackson.databind.ObjectMapper;
import org.apache.http.HttpHeaders;
import org.apache.http.HttpResponse;
import org.apache.http.HttpStatus;
import org.apache.http.client.methods.RequestBuilder;
import org.apache.http.client.utils.HttpClientUtils;
import org.apache.http.entity.ContentType;
import org.apache.http.entity.StringEntity;
import org.apache.http.message.BasicHeader;
import org.apache.http.util.EntityUtils;
import org.apache.maven.plugin.MojoExecutionException;
import org.apache.maven.plugin.MojoFailureException;
import org.apache.maven.plugins.annotations.LifecyclePhase;
import org.apache.maven.plugins.annotations.Mojo;
import org.apache.maven.plugins.annotations.Parameter;
import org.apache.maven.plugins.annotations.ResolutionScope;

/**
 * @author Christoph Deppisch
 * @since 2.7.4
 */
@Mojo(name = "test", defaultPhase = LifecyclePhase.INTEGRATION_TEST, requiresDependencyResolution = ResolutionScope.TEST)
public class RunTestMojo extends AbstractCitrusRemoteMojo {

    /** Global url encoding */
    private static final String ENCODING = "UTF-8";

    @Parameter(property = "citrus.remote.skip.test", defaultValue = "false")
    protected boolean skipRun;

    /**
     * Run configuration for test execution on remote server.
     */
    @Parameter
    private RunConfiguration run;

    /**
     * Object mapper for JSON response to object conversion.
     */
    private ObjectMapper objectMapper = new ObjectMapper();

    @Override
    public void doExecute() throws MojoExecutionException, MojoFailureException {
        if (skipRun) {
            return;
        }

        if (run == null) {
            run = new RunConfiguration();
        }

        if (!run.hasClasses() && !run.hasPackages()) {
            runAllTests();
        }

        if (run.hasClasses()) {
            runClasses(run.getClasses());
        }

        if (run.hasPackages()) {
            runPackages(run.getPackages());
        }
    }

    private void runPackages(List packages) throws MojoExecutionException {
        TestRunConfiguration runConfiguration = new TestRunConfiguration();

        runConfiguration.setEngine(run.getEngine());
        runConfiguration.setPackages(packages);

        if (run.getIncludes() != null) {
            runConfiguration.setIncludes(run.getIncludes().toArray(new String[run.getIncludes().size()]));
        }

        if (run.getSystemProperties() != null) {
            runConfiguration.addDefaultProperties(run.getSystemProperties());
        }

        runTests(runConfiguration);
    }

    private void runClasses(List classes) throws MojoExecutionException {
        TestRunConfiguration runConfiguration = new TestRunConfiguration();

        runConfiguration.setEngine(run.getEngine());
        runConfiguration.setTestClasses(classes.stream()
                                                .map(TestClass::fromString)
                                                .collect(Collectors.toList()));

        if (run.getSystemProperties() != null) {
            runConfiguration.addDefaultProperties(run.getSystemProperties());
        }

        runTests(runConfiguration);
    }

    private void runAllTests() throws MojoExecutionException {
        TestRunConfiguration runConfiguration = new TestRunConfiguration();

        runConfiguration.setEngine(run.getEngine());
        if (run.getIncludes() != null) {
            runConfiguration.setIncludes(run.getIncludes().toArray(new String[run.getIncludes().size()]));
        }

        if (run.getSystemProperties() != null) {
            runConfiguration.addDefaultProperties(run.getSystemProperties());
        }

        runTests(runConfiguration);
    }

    /**
     * Invokes run tests remote service and provide response message. If async mode is used the service is called with request method PUT
     * that creates a new run job on the server. The test results are then polled with multiple requests instead of processing the single synchronous response.
     *
     * @param runConfiguration
     * @return
     * @throws MojoExecutionException
     */
    private void runTests(TestRunConfiguration runConfiguration) throws MojoExecutionException {
        HttpResponse response = null;

        try {
            RequestBuilder requestBuilder;

            if (run.isAsync()) {
                requestBuilder = RequestBuilder.put(getServer().getUrl() + "/run");
            } else {
                requestBuilder = RequestBuilder.post(getServer().getUrl() + "/run");
            }

            requestBuilder.addHeader(new BasicHeader(HttpHeaders.ACCEPT, ContentType.APPLICATION_JSON.getMimeType()));

            StringEntity body = new StringEntity(new ObjectMapper().writeValueAsString(runConfiguration), ContentType.APPLICATION_JSON);
            requestBuilder.setEntity(body);

            response = getHttpClient().execute(requestBuilder.build());

            if (HttpStatus.SC_OK != response.getStatusLine().getStatusCode()) {
                throw new MojoExecutionException("Failed to run tests on remote server: " + EntityUtils.toString(response.getEntity()));
            }

            if (run.isAsync()) {
                HttpClientUtils.closeQuietly(response);
                handleTestResults(pollTestResults());
            } else {
                handleTestResults(objectMapper.readValue(response.getEntity().getContent(), RemoteResult[].class));
            }
        } catch (IOException e) {
            throw new MojoExecutionException("Failed to run tests on remote server", e);
        } finally {
            HttpClientUtils.closeQuietly(response);
        }
    }

    /**
     * When using async test execution mode the client does not synchronously wait for test results as it might lead to read timeouts. Instead
     * this method polls for test results and waits for the test execution to completely finish.
     *
     * @return
     * @throws MojoExecutionException
     */
    private RemoteResult[] pollTestResults() throws MojoExecutionException {
        HttpResponse response = null;
        try {
            do {
                HttpClientUtils.closeQuietly(response);
                response = getHttpClient().execute(RequestBuilder.get(getServer().getUrl() + "/results")
                        .addHeader(new BasicHeader(HttpHeaders.ACCEPT, ContentType.APPLICATION_JSON.getMimeType()))
                        .addParameter("timeout", String.valueOf(run.getPollingInterval()))
                        .build());

                if (HttpStatus.SC_PARTIAL_CONTENT == response.getStatusLine().getStatusCode()) {
                    getLog().info("Waiting for remote tests to finish ...");
                    getLog().info(Stream.of(objectMapper.readValue(response.getEntity().getContent(), RemoteResult[].class))
                            .map(RemoteResult::toTestResult).map(result -> result.isSkipped() ? "x" : (result.isSuccess() ? "+" : "-")).collect(Collectors.joining()));
                }
            } while (HttpStatus.SC_PARTIAL_CONTENT == response.getStatusLine().getStatusCode());

            if (HttpStatus.SC_OK != response.getStatusLine().getStatusCode()) {
                throw new MojoExecutionException("Failed to get test results from remote server: " + EntityUtils.toString(response.getEntity()));
            }

            return objectMapper.readValue(response.getEntity().getContent(), RemoteResult[].class);
        } catch (IOException e) {
            throw new MojoExecutionException("Failed to get test results from remote server", e);
        } finally {
            HttpClientUtils.closeQuietly(response);
        }
    }

    /**
     * Check test results for failures.
     * @param results
     * @throws IOException
     */
    private void handleTestResults(RemoteResult[] results) {
        StringWriter resultWriter = new StringWriter();
        resultWriter.append(String.format("%n"));

        TestResults testResults = new TestResults();
        Arrays.stream(results).forEach(remoteResult -> testResults.addResult(RemoteResult.toTestResult(remoteResult)));

        OutputStreamReporter reporter = new OutputStreamReporter(resultWriter);
        reporter.generate(testResults);
        getLog().info(resultWriter.toString());

        if (getReport().isHtmlReport()) {
            HtmlReporter htmlReporter = new HtmlReporter();
            htmlReporter.setReportDirectory(getOutputDirectory().getPath() + File.separator + getReport().getDirectory());
            htmlReporter.generate(testResults);
        }

        SummaryReporter summaryReporter = new SummaryReporter();
        summaryReporter.setReportDirectory(getOutputDirectory().getPath() + File.separator + getReport().getDirectory());
        summaryReporter.setReportFileName(getReport().getSummaryFile());
        summaryReporter.generate(testResults);

        getAndSaveReports();
    }

    private void getAndSaveReports() {
        if (!getReport().isSaveReportFiles()) {
            return;
        }

        HttpResponse response = null;
        String[] reportFiles = {};
        try {
            response = getHttpClient().execute(RequestBuilder.get(getServer().getUrl() + "/results/files")
                    .addHeader(new BasicHeader(HttpHeaders.ACCEPT, ContentType.APPLICATION_XML.getMimeType()))
                    .build());

            if (HttpStatus.SC_OK != response.getStatusLine().getStatusCode()) {
                getLog().warn("Failed to get test reports from remote server");
            }

            reportFiles = objectMapper.readValue(response.getEntity().getContent(), String[].class);
        } catch (IOException e) {
            getLog().warn("Failed to get test reports from remote server", e);
        } finally {
            HttpClientUtils.closeQuietly(response);
        }

        File citrusReportsDirectory = new File(getOutputDirectory() + File.separator + getReport().getDirectory());
        if (!citrusReportsDirectory.exists()) {
            if (!citrusReportsDirectory.mkdirs()) {
                throw new CitrusRuntimeException("Unable to create reports output directory: " + citrusReportsDirectory.getPath());
            }
        }

        File junitReportsDirectory = new File(citrusReportsDirectory, "junitreports");
        if (!junitReportsDirectory.exists()) {
            if (!junitReportsDirectory.mkdirs()) {
                throw new CitrusRuntimeException("Unable to create JUnit reports directory: " + junitReportsDirectory.getPath());
            }
        }

        JUnitReporter jUnitReporter = new JUnitReporter();
        loadAndSaveReportFile(new File(citrusReportsDirectory, String.format(jUnitReporter.getReportFileNamePattern(), jUnitReporter.getSuiteName())), getServer().getUrl() + "/results/suite", ContentType.APPLICATION_XML.getMimeType());

        Stream.of(reportFiles)
            .map(reportFile -> new File(junitReportsDirectory, reportFile))
            .forEach(reportFile -> {
                try {
                    loadAndSaveReportFile(reportFile, getServer().getUrl() + "/results/file/" + URLEncoder.encode(reportFile.getName(), ENCODING), ContentType.APPLICATION_XML.getMimeType());
                } catch (IOException e) {
                    getLog().warn("Failed to get report file: " + reportFile.getName(), e);
                }
            });
    }

    /**
     * Get report file content from server and save content to given file on local file system.
     * @param reportFile
     * @param serverUrl
     * @param contentType
     */
    private void loadAndSaveReportFile(File reportFile, String serverUrl, String contentType) {
        HttpResponse fileResponse = null;
        try {
            fileResponse = getHttpClient().execute(RequestBuilder.get(serverUrl)
                    .addHeader(new BasicHeader(HttpHeaders.ACCEPT, contentType))
                    .build());

            if (HttpStatus.SC_OK != fileResponse.getStatusLine().getStatusCode()) {
                getLog().warn("Failed to get report file: " + reportFile.getName());
                return;
            }

            getLog().info("Writing report file: " + reportFile);
            FileUtils.writeToFile(fileResponse.getEntity().getContent(), reportFile);
        } catch (IOException e) {
            getLog().warn("Failed to get report file: " + reportFile.getName(), e);
        } finally {
            HttpClientUtils.closeQuietly(fileResponse);
        }
    }

    /**
     * Sets the tests.
     *
     * @param tests
     */
    public void setTests(RunConfiguration tests) {
        this.run = tests;
    }
}




© 2015 - 2025 Weber Informatics LLC | Privacy Policy