org.linuxstuff.maven.TrinidadMojo Maven / Gradle / Ivy
Go to download
Show more of this group Show more artifacts with this name
Show all versions of trinidad-maven-plugin Show documentation
Show all versions of trinidad-maven-plugin Show documentation
Trinidad is a set of extensions and additional runners for the FitNesse acceptance test management tool.
package org.linuxstuff.maven;
import org.apache.maven.plugin.AbstractMojo;
import org.apache.maven.plugin.MojoExecutionException;
import java.io.File;
import java.lang.reflect.InvocationTargetException;
import java.lang.reflect.Method;
import java.net.URL;
import java.net.URLClassLoader;
import java.util.List;
import fitnesse.junit.*;
import fitnesse.responders.run.ResultsListener;
/**
* Goal which runs a trinidad test execution.
*
* @goal run-tests
* @phase integration-test
* @requiresDependencyResolution test
*/
public class TrinidadMojo extends AbstractMojo {
/**
* this is an embedded resource parameter, it is set automatically using maven - ignore it
*
* @parameter expression="${project}"
*/
private org.apache.maven.project.MavenProject mavenProject;
/**
* The URI for the result repository (output directory if using a file result repository).
*
* @parameter expression="${trinidad.output}" default-value="${project.build.directory}/trinidad"
* @required
*/
private String resultRepositoryUri;
/**
* The URI for the test repository. The format depends on the test repository type. For fitnesse test repositories, this is the path to the main
* fitnesse
*
* @parameter expression="${trinidad.test.location}"
* @required
*/
private String testRepositoryUri;
/**
* Set this to true for Maven to break the build if any of the tests have failed. Leave it set to false to just print out a warning
*
* @parameter default-value="false"
*/
private boolean breakBuildOnFailure;
/**
* Set this to true for Maven to stop running tests after the first failed test/suite. Leave it set to false to run all tests regardless of
* failures.
*
* @parameter default-value="false"
*/
private boolean stopAfterFirstFailure;
/**
* A set of suite names to execute.
*
* @parameter
*/
private String[] suites = new String[0];
/**
* A set of test names to execute
*
* @parameter
*/
private String[] tests = new String[0];
/**
* a single test to execute
*
* @parameter alias="test" expression="${trinidad.run.test}"
*/
private String singleTest = null;
/**
* a single test to execute
*
* @parameter alias="suite" expression="${trinidad.run.suite}"
*/
private String singleSuite = null;
/**
* Whether or not to skip test run. This aligns with how surefire works.
*
* @parameter default-value="false" expression="${maven.test.skip}"
*/
private boolean skipTest;
/**
* Optional listener class name for extending test instrumentation and reporting. The class should implement FitNesse ResultListener interface
*
* @parameter default-value="" expression="${trinidad.listener}"
*/
private String listenerClass;
void setTestRepositoryUri(String testRepositoryUri) {
this.testRepositoryUri = testRepositoryUri;
}
void setResultRepositoryUri(String resultRepositoryUri) {
this.resultRepositoryUri = resultRepositoryUri;
}
void setSingleSuite(String singleSuite) {
this.singleSuite = singleSuite;
}
void setSingleTest(String singleTest) {
this.singleTest = singleTest;
}
public void execute() throws MojoExecutionException {
if (this.skipTest) {
getLog().info("Skipping tests.");
return;
}
processDefaults();
createOutputDirectory();
final ClassLoader cl = initProjectTestClassLoader();
Thread runnerThread = new Thread(new Runnable() {
public void run() {
try {
Object testRunnerInstance = loadTestRunner(cl);
runIndividualTests(testRunnerInstance);
runSuites(testRunnerInstance);
} catch (Exception e) {
throw new Error(e);
}
}
});
runnerThread.setContextClassLoader(cl);
runnerThread.start();
try {
runnerThread.join();
} catch (InterruptedException e) {
getLog().error(e);
throw new MojoExecutionException("exception in the mojo runner thread", e);
}
if (breakBuildOnFailure && totalWrongOrException > 0)
throw new MojoExecutionException("Acceptance test run failed. Total " + totalWrongOrException
+ " failing tests or exceptions. See log for more information.");
}
private void createOutputDirectory() {
File output = new File(this.resultRepositoryUri);
if (!output.exists())
output.mkdirs();
}
private void runSuites(Object testRunnerInstance) throws NoSuchMethodException, IllegalAccessException, InvocationTargetException,
NoSuchFieldException, MojoExecutionException {
Method runSuite = testRunnerInstance.getClass().getMethod("runSuite", String.class);
for (String suite : suites) {
if (stopAfterFirstFailure && totalWrongOrException > 0)
break;
getLog().info("running suite=" + suite);
Object counts = runSuite.invoke(testRunnerInstance, suite);
int wrongOrException = getWrongPlusExceptions(counts);
totalWrongOrException += wrongOrException;
}
}
private int totalWrongOrException = 0;
private void runIndividualTests(Object testRunnerInstance) throws NoSuchMethodException, IllegalAccessException, InvocationTargetException,
NoSuchFieldException, MojoExecutionException {
Method runTest = testRunnerInstance.getClass().getMethod("runTest", String.class);
for (String test : tests) {
if (stopAfterFirstFailure && totalWrongOrException > 0)
break;
getLog().info("running test=" + test);
Object counts = runTest.invoke(testRunnerInstance, test);
int wrongOrException = getWrongPlusExceptions(counts);
totalWrongOrException += wrongOrException;
}
}
private Object loadTestRunner(ClassLoader cl) throws ClassNotFoundException, InstantiationException, IllegalAccessException,
NoSuchMethodException, InvocationTargetException {
Object testRunnerInstance;
Class> c = cl.loadClass(TestHelper.class.getName());
if (listenerClass != null && !("".equals(listenerClass))) {
Object listener = cl.loadClass(listenerClass).newInstance();
getLog().debug("Loaded listener:" + listenerClass);
testRunnerInstance = c.getConstructor(String.class, String.class, cl.loadClass(ResultsListener.class.getName())).newInstance(
this.testRepositoryUri, this.resultRepositoryUri, listener);
} else {
testRunnerInstance = c.getConstructor(String.class, String.class).newInstance(this.testRepositoryUri, this.resultRepositoryUri);
}
getLog().debug("loaded test runner:" + testRunnerInstance);
return testRunnerInstance;
}
private int getWrongPlusExceptions(Object counts) throws IllegalAccessException, NoSuchFieldException {
int wrong = counts.getClass().getField("wrong").getInt(counts);
int exceptions = counts.getClass().getField("exceptions").getInt(counts);
int wrongOrException = wrong + exceptions;
return wrongOrException;
}
private void processDefaults() {
if (singleTest != null)
tests = new String[] { singleTest };
if (singleSuite != null)
suites = new String[] { singleSuite };
}
private ClassLoader initProjectTestClassLoader() throws MojoExecutionException {
if (mavenProject == null)
return getClass().getClassLoader();
try {
List classpath = mavenProject.getTestClasspathElements();
getLog().debug("class path=" + classpath);
URL[] urlArray = new URL[classpath.size()];
for (int i = 0; i < classpath.size(); i++) {
urlArray[i] = new File(classpath.get(i)).toURI().toURL();
}
return new URLClassLoader(urlArray);
} catch (Exception e) {
throw new MojoExecutionException("class loader initialisation failed", e);
}
}
}