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

com.greenpepper.maven.plugin.SpecificationRunnerMojo Maven / Gradle / Ivy

The newest version!
/*
 * Copyright (c) 2007 Pyxis Technologies inc.
 * This 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 2 of the License, or
 * (at your option) any later version.
 * This software 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 this program; if not, write to the Free Software
 * Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA,
 * or see the FSF site: http://www.fsf.org.
 */

package com.greenpepper.maven.plugin;

import com.google.common.util.concurrent.ThreadFactoryBuilder;
import com.greenpepper.Statistics;
import com.greenpepper.document.GreenPepperInterpreterSelector;
import com.greenpepper.maven.plugin.runner.Runner;
import com.greenpepper.maven.plugin.runner.RunnerTask;
import com.greenpepper.maven.plugin.utils.NullStatisticsListener;
import com.greenpepper.maven.plugin.utils.ProjectsIndex;
import com.greenpepper.maven.plugin.utils.RepositoryIndex;
import com.greenpepper.maven.plugin.utils.TestResultsIndex;
import com.greenpepper.repository.DocumentRepository;
import com.greenpepper.repository.FileSystemRepository;
import com.greenpepper.runner.CompositeSpecificationRunnerMonitor;
import com.greenpepper.runner.RecorderMonitor;
import com.greenpepper.runner.RunnerStatistics;
import com.greenpepper.runner.SpecificationRunnerMonitor;
import com.greenpepper.runner.repository.DocumentNeverImplementedException;
import com.greenpepper.server.domain.*;
import com.greenpepper.util.IOUtil;
import org.apache.commons.io.FileUtils;
import org.apache.commons.lang3.StringUtils;
import org.apache.maven.artifact.Artifact;
import org.apache.maven.plugin.MojoExecutionException;
import org.apache.maven.plugin.MojoFailureException;
import org.apache.maven.project.MavenProject;
import org.jsoup.Jsoup;
import org.jsoup.select.Elements;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;

import java.io.*;
import java.net.MalformedURLException;
import java.net.URISyntaxException;
import java.net.URL;
import java.net.URLClassLoader;
import java.util.*;
import java.util.concurrent.*;
import java.util.jar.JarEntry;
import java.util.jar.JarFile;

import static com.greenpepper.maven.plugin.runner.Runner.DEFAULT_RUNNER_NAME;
import static com.greenpepper.util.URIUtil.escapeFileSystemForbiddenCharacters;
import static java.lang.String.format;
import static java.util.Arrays.asList;
import static org.apache.commons.io.FileUtils.*;
import static org.apache.commons.lang3.StringUtils.*;

/**
 * Run the specification testing.
 *
 * @goal run
 * @phase integration-test
 * @requiresDependencyResolution test
 * @description Runs GreenPepper specifications
 * @author oaouattara
 * @version $Id: $Id
 */
@SuppressWarnings("JavaDoc")
public class SpecificationRunnerMojo extends SpecificationNavigatorMojo {

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

    private static final String HTML_EXTENSION = ".html";

    private class RunnerResult {
        private final Future future;
        private final RunnerTask runnerTask;

        RunnerResult(RunnerTask runnerTask, Future future) {
            this.runnerTask = runnerTask;
            this.future = future;
        }
    }

    /**
     * Set this to 'true' to bypass greenpepper tests entirely.
     * Its use is NOT RECOMMENDED, but quite convenient on occasion.
     *
     * @parameter property="maven.greenpepper.test.skip" default-value="false"
     */
    @SuppressWarnings("unused")
    private boolean skip;

    /**
     * Project fixture classpath.
     * @parameter property="project.runtimeClasspathElements"
     * @required
     * @readonly
     */
    List classpathElements;

    /**
     * The directory where compiled fixture classes go.
     *
     * @parameter default-value="${project.build.directory}/fixture-test-classes"
     * @required
     */
    @SuppressWarnings("unused")
    private File fixtureOutputDirectory;

    /**
     * The SystemUnderDevelopment class to use
     * @parameter default-value="com.greenpepper.systemunderdevelopment.DefaultSystemUnderDevelopment"
     * @required
     */
    String systemUnderDevelopment;

    /**
     * The {@link com.greenpepper.systemunderdevelopment.SystemUnderDevelopment} constructor args.
     * This parameter is optionnal and can be achieved by appending them to the systemUnderDevelopment parameter.
     * @parameter
     */
    String systemUnderDevelopmentArgs;

    /**
     * @parameter property="plugin.artifacts"
     * @required
     * @readonly
     */
    List pluginDependencies;

    /**
     * Set this to 'true' to stop the execution on a failure.
     * @parameter property="maven.greenpepper.test.stop" default-value="false"
     */
    @SuppressWarnings("unused")
    private boolean stopOnFirstFailure;

    /**
     * Set the locale for the execution.
     * @parameter property="maven.greenpepper.locale"
     */
    String locale;

    /**
     * Set the Selector class.
     * @parameter property="maven.greenpepper.selector"
     *            default-value="com.greenpepper.document.GreenPepperInterpreterSelector"
     */
    String selector;

    /**
     * Set the Debug mode.
     *
     * @parameter property="maven.greenpepper.debug" default-value="false"
     */
    boolean debug;

    /**
     * Set this to true to ignore a failure during testing.
     * Its use is NOT RECOMMENDED, but quite convenient on occasion.
     *
     * @parameter property="maven.greenpepper.test.failure.ignore" default-value="false"
     */
    @SuppressWarnings("unused")
    private boolean testFailureIgnore;

    /**
     * Set this to true to output the logs only in the log file and not in the console.
     *
     * @parameter property="maven.greenpepper.redirect.output" default-value="false"
     */
    @SuppressWarnings("unused")
    private boolean redirectOutputToFile;

    /**
     * Set this property to true to launch only new specifications + failed ones.
     *
     * @parameter property="maven.greenpepper.resume" default-value="false"
     */
    boolean resume;

    /**
     * Set this to a Specification name to run only this test.
     * The test is searched inside the default repository.
     *
     * @parameter property="gp.test"
     */
    String testSpecification;

    /**
     * Set this to a Specification name to run only this test.
     * The test is searched inside the default repository.
     *
     * @parameter property="gp.testOutput"
     */
    String testSpecificationOutput;

    /**
     * Set this to a Repository name defined in the pom.xml.
     * This option is only used in case -Dgp.test is used.
     *
     * @parameter property="gp.repo"
     */
    String selectedRepository;

    /**
     * Launch the test in the Maven process if false. Or fork a java process if true.
     *
     * @parameter property="maven.greenpepper.fork" default-value="false"
     */
    boolean fork;

    /**
     * The maximum number of default runner processes that needs to be spawn;
     *
     * @parameter property="maven.greenpepper.forkcount" default=1
     */
    Integer forkCount;

    /**
     * The Java Virtual Machine path to use for the default runner in fork mode.
     *
     * @parameter property="maven.greenpepper.jvm" default-value="java"
     */
    @SuppressWarnings("FieldCanBeLocal")
    private String jvm = "java";

    /**
     * Additionnal JAVA Options to be added to the java command in fork mode.
     *
     * This is only used in FORK mode and for the default runner.
     *
     * @parameter property="maven.greenpepper.javaoptions"
     */
    String javaOptions;


    /**
     * When launching the tests in a fork, we create a default runner. You can exclude this default runner from the
     * testing process if you want to configure your owns.
     *
     * @parameter property="maven.greenpepper.excludedefaultrunner" default-value=false
     */
    boolean excludeDefaultRunner;

    /**
     * The list of runners that can be associated to repositories for testing.
     *
     * @parameter
     */
    List runners;

    /**
     * @component
     */
    protected MavenProject project;

    private HashMap executorMap = new HashMap();
    HashMap runnerMap = new HashMap();
    private LinkedHashSet runnerResults = new LinkedHashSet();

    RunnerStatistics runnerStatistics;

    private boolean testFailed;
    private boolean exceptionOccured;
    HashMap testResultsIndexes =  new HashMap();

    /**
     * 

Constructor for SpecificationRunnerMojo.

*/ public SpecificationRunnerMojo() { this.runnerStatistics = new RunnerStatistics(); } /** *

execute.

* * @throws org.apache.maven.plugin.MojoExecutionException if any. * @throws org.apache.maven.plugin.MojoFailureException if any. */ public void execute() throws MojoExecutionException, MojoFailureException { if (skip) { getLog().info("Not executing specifications."); } else { prepareReportsDir(); prepareRunnerExecutors(); printBanner(); try { runAllTests(); } finally { printFooter(); for (TestResultsIndex testResultsIndex : testResultsIndexes.values()) { testResultsIndex.dump(); } } checkTestsResults(); } } private void prepareRunnerExecutors() { if (runners == null || runners.isEmpty()) { runners = new ArrayList(); if ( !excludeDefaultRunner ) { runners.add(getDefaultRunner()); } } for (Runner runner : runners) { ThreadFactory threadFactory = new ThreadFactoryBuilder().setNameFormat(runner.getName()+ "-%d").build(); ExecutorService executorService = Executors.newFixedThreadPool(runner.getForkCount(), threadFactory); executorMap.put(runner.getName(), executorService); runnerMap.put(runner.getName(), runner); if (fork) { runner.setRedirectOutputToFile(true); } } } private void checkTestsResults() throws MojoExecutionException, MojoFailureException { if (exceptionOccured) notifyExceptionsOccured(); if (testFailed) notifyTestsFailed(); } private void notifyExceptionsOccured() throws MojoExecutionException { if (testFailureIgnore) { getLog().error("Some greenpepper tests did not run\n"); } else { throw new MojoExecutionException("Some greenpepper tests did not run"); } } private void notifyTestsFailed() throws MojoFailureException { if (!testResultsIndexes.isEmpty()) { System.out.println("List of failed tests"); for (Map.Entry indexEntry : testResultsIndexes.entrySet()) { String repoName = indexEntry.getKey(); TestResultsIndex testResultsIndex = indexEntry.getValue(); for (Map.Entry entry : testResultsIndex.getNameToInfo().entrySet()) { Statistics statistics = entry.getValue().getStatistics(); if (statistics.hasFailed()) { System.out.println(format("\t %s (Repository: %s) (%s)", entry.getKey(), repoName, statistics)); } } } System.out.println(); System.out.println("You can run the failed tests using the resume option '-Dmaven.greenpepper.resume=true'"); System.out.println(); } if (testFailureIgnore) { getLog().error("There were greenpepper tests failures\n"); } else { throw new MojoFailureException("There were greenpepper tests failures"); } } private void printBanner() { System.out.println(); System.out.println("-----------------------------------------------------"); System.out.println(" G R E E N P E P P E R S P E C I F I C A T I O N S "); System.out.println("-----------------------------------------------------"); System.out.println(); } private void runAllTests() throws MojoExecutionException, MojoFailureException { if (StringUtils.isNotEmpty(testSpecification)) { // Locate default repository Repository defaultRepository = null; if (repositories.size() == 1) { defaultRepository = repositories.get(0); } else { boolean repositorySelected = StringUtils.isNotEmpty(selectedRepository); if (repositorySelected) { defaultRepository = extractSelectedRepository(); } else { for (Repository repository : repositories) { if (repository.isDefault()) { defaultRepository = repository; break; } } } } if (defaultRepository == null) { throw new MojoExecutionException("A default repository should be set when using '-Dgp.test='. Use '-Dgp.repo=' or specify it in the pom.xml"); } // Run the test runSingleTest(defaultRepository, testSpecification); checkAsynchTasks(); } else { boolean repositorySelected = StringUtils.isNotEmpty(selectedRepository); if (repositorySelected) { runAllIn(extractSelectedRepository()); } else { for (Repository repository : repositories) { if (shouldStop()) { break; } runAllIn(repository); } } } } private Repository extractSelectedRepository() throws MojoExecutionException { for (Repository repository : repositories) { if (StringUtils.equalsIgnoreCase(selectedRepository, repository.getName())) { return repository; } } throw new MojoExecutionException(format("Repository '%s' not found in the list of repository.", selectedRepository)); } private void checkAsynchTasks() { for (RunnerResult runnerResult : runnerResults) { try { // This will wait for this Task completion runnerResult.future.get(); RecorderMonitor recorder = runnerResult.runnerTask.getRecorder(); exceptionOccured |= recorder.hasException(); testFailed |= recorder.hasTestFailures(); registerStatistics(recorder); } catch (InterruptedException e) { getLog().error(format("The task [%s] has been interrupted", runnerResult.runnerTask.getSpecification().getName())); } catch (ExecutionException e) { getLog().error(format("The task [%s] has failed", runnerResult.runnerTask.getSpecification().getName()), e); } } runnerResults.clear(); } private void runAllIn(Repository repository) throws MojoExecutionException, MojoFailureException { List repositorySpecifications; try { repositorySpecifications = listRepositorySpecifications(repository); } catch (Exception e) { throw new MojoExecutionException(format("Couldn't list repository '%s' specifications", repository.getName()), e); } try { extractHtmlReportSummary(); prepareProjectIndex(repository); prepareTestResultsIndex(repository); } catch (URISyntaxException e) { throw new MojoExecutionException(format("Couldn't prepare the report for repository '%s'", repository.getName()), e); } catch (IOException e) { throw new MojoExecutionException(format("Couldn't prepare the report for repository '%s'", repository.getName()), e); } repository.getTests().clear(); repository.getTests().addAll(repositorySpecifications); runTestsIn(repository); checkAsynchTasks(); System.out.println(); System.out.println(format("See the report at %s", getFile(reportsDirectory, "index" + HTML_EXTENSION).getAbsolutePath())); System.out.println(); } private void prepareProjectIndex(Repository repository) throws IOException { File storage = new File(reportsDirectory, "index.json"); ProjectsIndex projectsIndex = new ProjectsIndex(storage); try { projectsIndex.load(); } catch (IOException e) { getLog().warn(format("index.json is corrupted. Start a new one. Cause: %s", e.getMessage())); FileUtils.moveFile(storage, new File(reportsDirectory, "index.json.orig")); } ProjectsIndex.ProjectInfo projectInfo = projectsIndex.getNameToInfo().get(repository.getName()); if (projectInfo == null) { projectInfo = new ProjectsIndex.ProjectInfo(); projectInfo.projectName = repository.getProjectName(); projectInfo.repoName = repository.getName(); projectInfo.repoId = getRepositoryMetaName(repository); projectInfo.systemUnderTest = repository.getSystemUnderTest(); projectInfo.startDate = ProjectsIndex.ProjectInfo.SIMPLE_DATE_FORMAT.format(new Date()); projectsIndex.getNameToInfo().put(repository.getName(), projectInfo); } else { projectInfo.startDate = ProjectsIndex.ProjectInfo.SIMPLE_DATE_FORMAT.format(new Date()); } projectsIndex.dump(); } private void prepareTestResultsIndex(Repository repository) throws IOException { File storage = getResultsIndexFile(repository); TestResultsIndex testResultsIndex = TestResultsIndex.newInstance(storage); testResultsIndexes.put(repository.getName(),testResultsIndex); } private void extractHtmlReportSummary() throws IOException, URISyntaxException { final String path = "html-summary-report"; final File jarFile = new File(getClass().getProtectionDomain().getCodeSource().getLocation().getPath()); forceMkdir(reportsDirectory); if(jarFile.isFile()) { // Run with JAR file JarFile jar = new JarFile(jarFile); Enumeration entries = jar.entries(); //gives ALL entries in jar while(entries.hasMoreElements()) { JarEntry jarEntry = entries.nextElement(); String name = jarEntry.getName(); if (name.startsWith(path)) { //filter according to the path File file = getFile(reportsDirectory, substringAfter(name, path)); if (jarEntry.isDirectory()) { forceMkdir(file); } else { forceMkdir(file.getParentFile()); if (!file.exists()) { copyInputStreamToFile(jar.getInputStream(jarEntry), file); } } } } jar.close(); } else { // Run with IDE URL url = getClass().getResource("/" + path); if (url != null) { File apps = FileUtils.toFile(url); if (apps.isDirectory()) { copyDirectory(apps, reportsDirectory); } else { throw new IllegalStateException(format("Internal resource '%s' should be a directory.", apps.getAbsolutePath())); } } else { throw new IllegalStateException(format("Internal resource '/%s' should be here.", path)); } } } File getResultsIndexFile(Repository repository) throws UnsupportedEncodingException { return new File(reportsDirectory, getRepositoryMetaName(repository) + ".results"); } private void runTestsIn(Repository repository) throws MojoExecutionException, MojoFailureException { if (!resume) { TestResultsIndex testResultsIndex = testResultsIndexes.get(repository.getName()); if (testResultsIndex != null) { testResultsIndex.getNameToInfo().clear(); } } for (String test : repository.getTests()) { if (shouldStop()) { break; } runSingleTest(repository, test); } } private void runSingleTest(Repository repository, String test) throws MojoExecutionException, MojoFailureException { if (resume) { // Resume set, we will run the test only if it's new or failing; TestResultsIndex testResultsIndex = testResultsIndexes.get(repository.getName()); if (testResultsIndex != null) { Map results = testResultsIndex.getNameToInfo(); if (results.containsKey(test) && !results.get(test).getStatistics().hasFailed()) { getLog().info(format("Skipping %s due to 'resume' option set", test)); return; } } } String repoCmdOption; boolean managingFileSystem; try { DocumentRepository documentRepository = repository.getDocumentRepository(); managingFileSystem = FileSystemRepository.class.isAssignableFrom(documentRepository.getClass()); } catch (Exception e) { throw new MojoFailureException("Unable to get the document repository", e); } if (managingFileSystem) { File projectBasedir = project.getBasedir(); repoCmdOption = repository.getType() + ";"; if (repository.getRoot() != null){ File relativeRoot = new File(repository.getRoot()); File absoluteDir; if (relativeRoot.getAbsoluteFile().compareTo(relativeRoot) == 0) { absoluteDir = relativeRoot; } else { absoluteDir = new File(projectBasedir,repository.getRoot()); } repoCmdOption += absoluteDir.getAbsolutePath(); } else { repoCmdOption += projectBasedir.getAbsolutePath(); } } else { repoCmdOption = repository.getType() + (repository.getRoot() != null ? ";" + repository.getRoot() : ""); } File repositoryReportsFolder = new File(reportsDirectory, repository.getName()); runnerStatistics.addToTotal(1); if (fork || isNotBlank(repository.getRunnerName())) { // If the repository specified a runner runInForkedRunner(repository, test, repositoryReportsFolder); } else { runInEmbeddedRunner(repository, test, repoCmdOption, repositoryReportsFolder); } } private void runInForkedRunner(Repository repository, String test, File repositoryReportsFolder) throws MojoExecutionException { File outputFile = new File(repositoryReportsFolder, test); SystemUnderTest systemUnderTest = new SystemUnderTest(); systemUnderTest.setName(repository.getSystemUnderTest()); systemUnderTest.setProject(Project.newInstance(repository.getProjectName())); Specification specification = Specification.newInstance(test); com.greenpepper.server.domain.Repository repositoryRunner = com.greenpepper.server.domain.Repository.newInstance(repository.getName()); RepositoryType repositoryType = RepositoryType.newInstance("FILE"); repositoryType.setRepositoryClass(repository.getType()); EnvironmentType java = EnvironmentType.newInstance("JAVA"); repositoryType.registerClassForEnvironment(repository.getType(), java); repositoryRunner.setBaseTestUrl(repository.getRoot()); repositoryRunner.setType(repositoryType); specification.setRepository(repositoryRunner); systemUnderTest.setFixtureFactory(systemUnderDevelopment); systemUnderTest.setFixtureFactoryArgs(systemUnderDevelopmentArgs); specification.setDialectClass(repository.getDialect()); String runnerName = repository.getRunnerName(); if (runnerName == null) { if (runnerMap.size() == 1) { runnerName = runnerMap.keySet().iterator().next(); } else { runnerName = DEFAULT_RUNNER_NAME; } } Runner defaultRunner = runnerMap.get(runnerName); ExecutorService executorService = executorMap.get(runnerName); if (defaultRunner != null && executorService != null ) { if (defaultRunner.getForkCount() == 1) { defaultRunner.setRedirectOutputToFile(redirectOutputToFile); } // We will try to get the external-link after the test (for version of Greepepper < 4.1 ) defaultRunner.setRepositoryIndex(this.repositoryIndexes.get(repository.getName())); TestResultsIndex testResultsIndex = testResultsIndexes.get(repository.getName()); RunnerTask runnerTask = new RunnerTask(specification, systemUnderTest, outputFile.getAbsolutePath(), defaultRunner, getLog(), testResultsIndex); if (defaultRunner.isIncludeProjectClasspath()) { TreeSet classpath = new TreeSet(); for (URL url : createClasspath()) { classpath.add(FileUtils.toFile(url).getAbsolutePath()); } systemUnderTest.setSutClasspaths(classpath); } Future future = executorService.submit(runnerTask); RunnerResult runnerResult = new RunnerResult(runnerTask, future); runnerResults.add(runnerResult); } else { getLog().warn(format("No runner found for executing %s in repository %s. Runner '%s' was specified (or falled back to)", specification.getName(), repository.getName(), runnerName)); } } private Runner getDefaultRunner() { List optionsList = new ArrayList(); appendOptionsList(optionsList); Runner defaultRunner = Runner.createDefault(jvm, javaOptions, optionsList); if (forkCount != null) { defaultRunner.setForkCount(forkCount); } return defaultRunner; } private void runInEmbeddedRunner(Repository repository, String test, String repoCmdOption, File repositoryReportsFolder) throws MojoExecutionException, MojoFailureException { String outputDir = repositoryReportsFolder.getAbsolutePath(); String systemUnderDevelopmentWithArgs = getFixtureFactoryWithArgs(); List args = new ArrayList(); args.addAll(asList("-f", systemUnderDevelopmentWithArgs, "-r", repoCmdOption, "-o", outputDir)); if (isNotBlank(repository.getDialect())) { List dialectOption = asList("-d", repository.getDialect()); args.addAll(dialectOption); } appendOptionsList(args); args.add(test); // Add the target output (which might have the same name as the test String output = null; if (StringUtils.isNoneEmpty(testSpecification, testSpecificationOutput)) { output = testSpecificationOutput; } else if (endsWithIgnoreCase(test, HTML_EXTENSION)) { output = test; } if (isNotBlank(output)) { args.add(output); } // try to define the output file File outputFile; if (isNotBlank(output)) { outputFile = getFile(outputDir, escapeFileSystemForbiddenCharacters(output)); } else { outputFile = getFile(outputDir, escapeFileSystemForbiddenCharacters(test)); } File outLogFile = new File(outputFile.getAbsolutePath() + "-output.log"); File errLogFile = new File(outputFile.getAbsolutePath() + "-err.log"); LogWriterMonitor logWriterMonitor = new LogWriterMonitor(outLogFile, errLogFile); TestMonitor testMonitor = new TestMonitor(getLog(), new NullStatisticsListener()); RecorderMonitor recorderMonitor = run(args, logWriterMonitor, testMonitor); TestResultsIndex testResultsIndex = testResultsIndexes.get(repository.getName()); if (testResultsIndex != null) { testResultsIndex.notify(test, recorderMonitor.getStatistics(), testMonitor.duration); } RepositoryIndex repositoryIndex = repositoryIndexes.get(repository.getName()); if (repositoryIndex != null && repositoryIndex.getNameToInfo().containsKey(test) && isBlank(repositoryIndex.getNameToInfo().get(test).getLink())) { if (!endsWithIgnoreCase(test, HTML_EXTENSION)) { outputFile = getFile(outputDir, escapeFileSystemForbiddenCharacters(test) + HTML_EXTENSION); } if (outputFile.isFile() && outputFile.canRead()) { try { String outputHTML = readFileToString(outputFile); recoverLinkInResult(test, outputHTML, repositoryIndex); } catch (Exception e) { getLog().debug(format("Could not read the output file '%s'. Cause : %s", outputFile.getAbsolutePath(), e.getMessage())); LOGGER.trace("full trace: ", e); } } } } private String getFixtureFactoryWithArgs() { String systemUnderDevelopmentWithArgs = systemUnderDevelopment; if (isNotBlank(systemUnderDevelopmentArgs)) { systemUnderDevelopmentWithArgs = systemUnderDevelopment + ";" + systemUnderDevelopmentArgs; } return systemUnderDevelopmentWithArgs; } public static void recoverLinkInResult(String specification, String htmlString, RepositoryIndex repositoryIndex) throws IOException { RepositoryIndex.SpecificationInfo specificationInfo = repositoryIndex.getNameToInfo().get(specification); if (isBlank(specificationInfo.getLink()) && isNotBlank(htmlString)) { LOGGER.trace("got new missing link in index for '{}'. trying to find it in the result output", specification); org.jsoup.nodes.Document resultOutput = Jsoup.parse(htmlString); Elements metaTags = resultOutput.head().getElementsByTag("meta"); String link = metaTags.select("[name=\"external-link\"]").attr("content"); if (isNotBlank(link)) { LOGGER.trace("Found {}", link); specificationInfo.setLink(link); repositoryIndex.dump(); } } } private RecorderMonitor run(List args, SpecificationRunnerMonitor... testMonitors) throws MojoExecutionException, MojoFailureException { DynamicCoreInvoker runner = new DynamicCoreInvoker(createClassLoader()); CompositeSpecificationRunnerMonitor monitors = new CompositeSpecificationRunnerMonitor(); for (SpecificationRunnerMonitor specificationRunnerMonitor : testMonitors) { monitors.add(specificationRunnerMonitor); } RecorderMonitor recorder = new RecorderMonitor(); monitors.add(recorder); runner.setMonitor(monitors); try { LOGGER.debug("Launching the test: {}", args); runner.run(toArray(args)); } catch (DocumentNeverImplementedException e) { LOGGER.info(DocumentRepository.THIS_SPECIFICATION_WAS_NEVER_SET_AS_IMPLEMENTED); } catch (Exception e) { exceptionOccured = true; throw new MojoExecutionException("Unable to run tests", e); } exceptionOccured |= recorder.hasException(); testFailed |= recorder.hasTestFailures(); registerStatistics(recorder); return recorder; } private void registerStatistics(RecorderMonitor recorder) { runnerStatistics.tally(recorder.getStatistics()); } private void printFooter() { System.out.println(); System.out.println(runnerStatistics); System.out.println(); } private ClassLoader createClassLoader() throws MojoExecutionException { URL[] classpath = createClasspath(); return new URLClassLoader(classpath, ClassLoader.getSystemClassLoader()); } private URL[] createClasspath() throws MojoExecutionException { List urls = new ArrayList(); if (classpathElements != null) { for (String classpathElement : classpathElements) { urls.add(toURL(new File(classpathElement))); } } urls.add(toURL(fixtureOutputDirectory)); if (!containsGreenPepperCore(urls)) { urls.add(getDependencyURL("greenpepper-core")); } urls.add(getDependencyURL("greenpepper-extensions-java")); urls.add(getDependencyURL("slf4j-api")); urls.add(getDependencyURL("jcl-over-slf4j")); return urls.toArray(new URL[urls.size()]); } private URL getDependencyURL(String name) throws MojoExecutionException { if (pluginDependencies != null && !pluginDependencies.isEmpty()) { for (Artifact artifact : pluginDependencies) { if (artifact.getArtifactId().equals(name) && artifact.getType().equals("jar")) return toURL(artifact.getFile()); } } throw new MojoExecutionException("Dependency not found: " + name); } private URL toURL(File f) throws MojoExecutionException { try { return f.toURI().toURL(); } catch (MalformedURLException e) { throw new MojoExecutionException("Invalid dependency: " + f.getAbsolutePath(), e); } } private boolean containsGreenPepperCore(List urls) { for (URL url : urls) { if (url.getFile().contains("greenpepper-core") && url.getFile().endsWith(".jar")) { return true; } } return false; } private void prepareReportsDir() throws MojoExecutionException { if (StringUtils.isAnyEmpty(testSpecification, testSpecificationOutput)) { try { IOUtil.createDirectoryTree(reportsDirectory); } catch (IOException e) { throw new MojoExecutionException("Could not create reports directory: " + reportsDirectory.getAbsolutePath()); } } } private boolean shouldStop() { return stopOnFirstFailure && runnerStatistics.hasFailure(); } private void appendOptionsList(List arguments) { if (!StringUtils.isEmpty(locale)) { arguments.add("--locale"); arguments.add(locale); } if (!StringUtils.isEmpty(selector) && !GreenPepperInterpreterSelector.class.getName().equals(selector)) { arguments.add("--selector"); arguments.add(selector); } if (stopOnFirstFailure) { arguments.add("--stop"); } if (debug) { arguments.add("--debug"); } } private String[] toArray(List args) { String[] arguments = new String[args.size()]; args.toArray(arguments); return arguments; } private class LogWriterMonitor implements SpecificationRunnerMonitor { private final File outLogFile; private final File errLogFile; private PrintStream sysout; private PrintStream syserr; LogWriterMonitor(File outLogFile, File errLogFile) { this.outLogFile = outLogFile; this.errLogFile = errLogFile; } @Override public void testRunning(String location) { getLog().debug(format("Creating Log files (by redirecting sysout and stderr) for: %s", location)); sysout = System.out; syserr = System.err; syserr.flush(); sysout.flush(); try { FileOutputStream output = openOutputStream(outLogFile); FileOutputStream err = openOutputStream(errLogFile); if (redirectOutputToFile) { System.setOut(new PrintStream(output)); System.setErr(new PrintStream(err)); } else { TeePrintStream teeoutput = new TeePrintStream(output, sysout); System.setOut(teeoutput); TeePrintStream teeErr = new TeePrintStream(err, syserr); System.setErr(teeErr); } } catch (IOException e) { System.setOut(sysout); System.setErr(syserr); getLog().warn(format("Could not create the log files. Cause: %s", e.getMessage())); getLog().debug("Could not create the log files.", e); } } @Override public void testDone(int rightCount, int wrongCount, int exceptionCount, int ignoreCount) { getLog().debug("Restoring stdout and stderr"); System.setOut(sysout); System.setErr(syserr); } @Override public void exceptionOccured(Throwable t) { } } private class TeePrintStream extends PrintStream { private final PrintStream second; TeePrintStream(OutputStream main, PrintStream second) { super(main); this.second = second; } /** * Closes the main stream. * The second stream is just flushed but not closed. * @see java.io.PrintStream#close() */ @Override public void close() { // just for documentation super.close(); } @Override public void flush() { super.flush(); second.flush(); } @SuppressWarnings("NullableProblems") @Override public void write(byte[] buf, int off, int len) { super.write(buf, off, len); second.write(buf, off, len); } @Override public void write(int b) { super.write(b); second.write(b); } @SuppressWarnings("NullableProblems") @Override public void write(byte[] b) throws IOException { super.write(b); second.write(b); } } }




© 2015 - 2024 Weber Informatics LLC | Privacy Policy