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

org.apache.maven.plugin.surefire.SurefireHelper Maven / Gradle / Ivy

There is a newer version: 3.5.2
Show newest version
/*
 * Licensed to the Apache Software Foundation (ASF) under one
 * or more contributor license agreements.  See the NOTICE file
 * distributed with this work for additional information
 * regarding copyright ownership.  The ASF licenses this file
 * to you 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 org.apache.maven.plugin.surefire;

import javax.annotation.Nonnull;

import java.io.File;
import java.util.ArrayList;
import java.util.Collection;
import java.util.Deque;
import java.util.LinkedList;
import java.util.List;

import org.apache.maven.execution.MavenExecutionRequest;
import org.apache.maven.execution.MavenSession;
import org.apache.maven.plugin.MojoExecutionException;
import org.apache.maven.plugin.MojoFailureException;
import org.apache.maven.plugin.surefire.log.PluginConsoleLogger;
import org.apache.maven.surefire.api.cli.CommandLineOption;
import org.apache.maven.surefire.api.suite.RunResult;
import org.apache.maven.surefire.api.testset.TestSetFailedException;
import org.apache.maven.surefire.booter.SurefireBooterForkException;

import static java.util.Collections.unmodifiableList;
import static org.apache.maven.surefire.api.booter.DumpErrorSingleton.DUMPSTREAM_FILE_EXT;
import static org.apache.maven.surefire.api.booter.DumpErrorSingleton.DUMP_FILE_EXT;
import static org.apache.maven.surefire.api.cli.CommandLineOption.LOGGING_LEVEL_DEBUG;
import static org.apache.maven.surefire.api.cli.CommandLineOption.LOGGING_LEVEL_ERROR;
import static org.apache.maven.surefire.api.cli.CommandLineOption.LOGGING_LEVEL_INFO;
import static org.apache.maven.surefire.api.cli.CommandLineOption.LOGGING_LEVEL_WARN;
import static org.apache.maven.surefire.api.cli.CommandLineOption.SHOW_ERRORS;
import static org.apache.maven.surefire.api.util.internal.DumpFileUtils.newFormattedDateFileName;
import static org.apache.maven.surefire.shared.lang3.SystemUtils.IS_OS_WINDOWS;

/**
 * Helper class for surefire plugins
 */
public final class SurefireHelper {
    private static final String DUMP_FILE_DATE = newFormattedDateFileName();

    public static final String DUMP_FILE_PREFIX = DUMP_FILE_DATE + "-jvmRun";

    public static final String DUMP_FILENAME_FORMATTER = DUMP_FILE_PREFIX + "%d" + DUMP_FILE_EXT;

    public static final String DUMPSTREAM_FILENAME_FORMATTER = DUMP_FILE_PREFIX + "%d" + DUMPSTREAM_FILE_EXT;

    public static final String DUMPSTREAM_FILENAME = DUMP_FILE_DATE + DUMPSTREAM_FILE_EXT;

    public static final String DUMP_FILENAME = DUMP_FILE_DATE + DUMP_FILE_EXT;

    public static final String EVENTS_BINARY_DUMP_FILENAME_FORMATTER = DUMP_FILE_DATE + "-jvmRun%d-events.bin";

    /**
     * The maximum path that does not require long path prefix on Windows.
* See {@code sun/nio/fs/WindowsPath} in * * OpenJDK * and MSDN article. *
* The maximum path is 260 minus 1 (NUL) but for directories it is 260 * minus 12 minus 1 (to allow for the creation of a 8.3 file in the directory). */ private static final int MAX_PATH_LENGTH_WINDOWS = 247; private static final String[] DUMP_FILES_PRINT = { "[date]" + DUMP_FILE_EXT, "[date]-jvmRun[N]" + DUMP_FILE_EXT, "[date]" + DUMPSTREAM_FILE_EXT, "[date]-jvmRun[N]" + DUMPSTREAM_FILE_EXT }; /** * The placeholder that is replaced by the executing thread's running number. The thread number * range starts with 1 * Deprecated. */ private static final String THREAD_NUMBER_PLACEHOLDER = "${surefire.threadNumber}"; /** * The placeholder that is replaced by the executing fork's running number. The fork number * range starts with 1 */ private static final String FORK_NUMBER_PLACEHOLDER = "${surefire.forkNumber}"; /** * Do not instantiate. */ private SurefireHelper() { throw new IllegalAccessError("Utility class"); } @Nonnull public static String replaceThreadNumberPlaceholders(@Nonnull String argLine, int threadNumber) { String threadNumberAsString = String.valueOf(threadNumber); return argLine.replace(THREAD_NUMBER_PLACEHOLDER, threadNumberAsString) .replace(FORK_NUMBER_PLACEHOLDER, threadNumberAsString); } public static File replaceForkThreadsInPath(File path, int replacement) { Deque dirs = new LinkedList<>(); File root = path; while (!root.exists()) { dirs.addFirst(replaceThreadNumberPlaceholders(root.getName(), replacement)); root = root.getParentFile(); } File replacedPath = root; for (String dir : dirs) { replacedPath = new File(replacedPath, dir); } return replacedPath; } public static String[] getDumpFilesToPrint() { return DUMP_FILES_PRINT.clone(); } public static void reportExecution( SurefireReportParameters reportParameters, RunResult result, PluginConsoleLogger log, Exception firstForkException) throws MojoFailureException, MojoExecutionException { boolean isError = firstForkException != null || result.isTimeout() || !result.isErrorFree(); boolean isTooFlaky = isTooFlaky(result, reportParameters); if (!isError && !isTooFlaky) { if (result.getCompletedCount() == 0 && failIfNoTests(reportParameters)) { throw new MojoFailureException( "No tests were executed! " + "(Set -DfailIfNoTests=false to ignore this error.)"); } return; } if (reportParameters.isTestFailureIgnore()) { String errorMessage = createErrorMessage(reportParameters, result, firstForkException); if (firstForkException instanceof SurefireBooterForkException) { throw new MojoExecutionException(errorMessage, firstForkException); } log.error(errorMessage); } else { throwException(reportParameters, result, firstForkException); } } public static List commandLineOptions(MavenSession session, PluginConsoleLogger log) { List cli = new ArrayList<>(); if (log.isErrorEnabled()) { cli.add(LOGGING_LEVEL_ERROR); } if (log.isWarnEnabled()) { cli.add(LOGGING_LEVEL_WARN); } if (log.isInfoEnabled()) { cli.add(LOGGING_LEVEL_INFO); } if (log.isDebugEnabled()) { cli.add(LOGGING_LEVEL_DEBUG); } MavenExecutionRequest request = session.getRequest(); if (request.isShowErrors()) { cli.add(SHOW_ERRORS); } String failureBehavior = request.getReactorFailureBehavior(); if (failureBehavior != null) { try { cli.add(CommandLineOption.valueOf(failureBehavior)); } catch (IllegalArgumentException e) { // CommandLineOption does not have specified enum as string. See getRequest() method in Maven Session. } } return unmodifiableList(cli); } public static void logDebugOrCliShowErrors(String s, PluginConsoleLogger log, Collection cli) { if (cli.contains(LOGGING_LEVEL_DEBUG)) { log.debug(s); } else if (cli.contains(SHOW_ERRORS)) { if (log.isDebugEnabled()) { log.debug(s); } else { log.info(s); } } } /** * Escape file path for Windows when the path is too long; otherwise returns {@code path}. *
* See * sun/nio/fs/WindowsPath for "long path" value explanation (=247), and * MSDN article * for detailed escaping strategy explanation: in short, {@code \\?\} prefix for path with drive letter * or {@code \\?\UNC\} for UNC path. * * @param path source path * @return escaped to platform path */ public static String escapeToPlatformPath(String path) { if (IS_OS_WINDOWS && path.length() > MAX_PATH_LENGTH_WINDOWS) { path = path.startsWith("\\\\") ? "\\\\?\\UNC\\" + path.substring(2) : "\\\\?\\" + path; } return path; } private static boolean failIfNoTests(SurefireReportParameters reportParameters) { return reportParameters.getFailIfNoTests(); } private static boolean isFatal(Exception firstForkException) { return firstForkException != null && !(firstForkException instanceof TestSetFailedException); } private static void throwException( SurefireReportParameters reportParameters, RunResult result, Exception firstForkException) throws MojoFailureException, MojoExecutionException { if (isFatal(firstForkException) || result.isInternalError()) { throw new MojoExecutionException( createErrorMessage(reportParameters, result, firstForkException), firstForkException); } else { throw new MojoFailureException( createErrorMessage(reportParameters, result, firstForkException), firstForkException); } } private static String createErrorMessage( SurefireReportParameters reportParameters, RunResult result, Exception firstForkException) { StringBuilder msg = new StringBuilder(512); if (result.isTimeout()) { msg.append("There was a timeout in the fork"); } else { if (result.getFailures() > 0) { msg.append("There are test failures."); } if (isTooFlaky(result, reportParameters)) { if (result.getFailures() > 0) { msg.append("\n"); } msg.append("There") .append(result.getFlakes() == 1 ? " is " : " are ") .append(result.getFlakes()) .append(result.getFlakes() == 1 ? " flake " : " flakes ") .append("and failOnFlakeCount is set to ") .append(reportParameters.getFailOnFlakeCount()) .append("."); } msg.append("\n\nPlease refer to ") .append(reportParameters.getReportsDirectory()) .append(" for the individual test results.") .append('\n') .append("Please refer to dump files (if any exist) ") .append(DUMP_FILES_PRINT[0]) .append(", ") .append(DUMP_FILES_PRINT[1]) .append(" and ") .append(DUMP_FILES_PRINT[2]) .append("."); } if (firstForkException != null && firstForkException.getLocalizedMessage() != null) { msg.append('\n').append(firstForkException.getLocalizedMessage()); } if (result.isFailure()) { msg.append('\n').append(result.getFailure()); } return msg.toString(); } private static boolean isTooFlaky(RunResult result, SurefireReportParameters reportParameters) { int failOnFlakeCount = reportParameters.getFailOnFlakeCount(); return failOnFlakeCount > 0 && result.getFlakes() >= failOnFlakeCount; } }




© 2015 - 2024 Weber Informatics LLC | Privacy Policy