diff --git a/core/src/main/java/hudson/tasks/junit/TestResult.java b/core/src/main/java/hudson/tasks/junit/TestResult.java index 13e815612187e0de9f522e2727f4aed408fec642..1025ce70cdc8d1184f95aded3700a3aa14af44d7 100644 --- a/core/src/main/java/hudson/tasks/junit/TestResult.java +++ b/core/src/main/java/hudson/tasks/junit/TestResult.java @@ -27,15 +27,10 @@ import hudson.AbortException; import hudson.Util; import hudson.model.AbstractBuild; import hudson.model.Run; +import hudson.tasks.test.AbstractTestResultAction; import hudson.tasks.test.MetaTabulatedResult; import hudson.tasks.test.TestObject; -import hudson.tasks.test.AbstractTestResultAction; import hudson.util.IOException2; -import org.apache.tools.ant.DirectoryScanner; -import org.dom4j.DocumentException; -import org.kohsuke.stapler.StaplerRequest; -import org.kohsuke.stapler.StaplerResponse; -import org.kohsuke.stapler.export.Exported; import java.io.File; import java.io.IOException; @@ -49,6 +44,12 @@ import java.util.List; import java.util.Map; import java.util.TreeMap; +import org.apache.tools.ant.DirectoryScanner; +import org.dom4j.DocumentException; +import org.kohsuke.stapler.StaplerRequest; +import org.kohsuke.stapler.StaplerResponse; +import org.kohsuke.stapler.export.Exported; + /** * Root of all the test results for one build. * @@ -153,15 +154,8 @@ public final class TestResult extends MetaTabulatedResult { for (String value : reportFiles) { File reportFile = new File(baseDir, value); // only count files that were actually updated during this build - if ( (buildTime-3000/*error margin*/ <= reportFile.lastModified()) || !checkTimestamps) { - if(reportFile.length()==0) { - // this is a typical problem when JVM quits abnormally, like OutOfMemoryError during a test. - SuiteResult sr = new SuiteResult(reportFile.getName(), "", ""); - sr.addCase(new CaseResult(sr,"","Test report file "+reportFile.getAbsolutePath()+" was length 0")); - add(sr); - } else { - parse(reportFile); - } + if ( (buildTime-3000/*error margin*/ <= reportFile.lastModified())) { + parsePossiblyEmpty(reportFile); parsed = true; } } @@ -183,7 +177,60 @@ public final class TestResult extends MetaTabulatedResult { Util.getTimeSpanString(buildTime-f.lastModified()))); } } + + + public void parse(long buildTime, Iterable reportFiles) throws IOException { + boolean parsed=false; + + for (File reportFile : reportFiles) { + // only count files that were actually updated during this build + if ( (buildTime-3000/*error margin*/ <= reportFile.lastModified())) { + parsePossiblyEmpty(reportFile); + parsed = true; + } + } + if(!parsed) { + long localTime = System.currentTimeMillis(); + if(localTime < buildTime-1000) /*margin*/ + // build time is in the the future. clock on this slave must be running behind + throw new AbortException( + "Clock on this slave is out of sync with the master, and therefore \n" + + "I can't figure out what test results are new and what are old.\n" + + "Please keep the slave clock in sync with the master."); + + File f = reportFiles.iterator().next(); + throw new AbortException( + String.format( + "Test reports were found but none of them are new. Did tests run? %n"+ + "For example, %s is %s old%n", f, + Util.getTimeSpanString(buildTime-f.lastModified()))); + } + + } + + /** + * Collect reports from the given report files + * + * @since TODO + */ + public void parse(Iterable reportFiles) throws IOException { + for (File reportFile : reportFiles) { + parsePossiblyEmpty(reportFile); + } + } + + private void parsePossiblyEmpty(File reportFile) throws IOException { + if(reportFile.length()==0) { + // this is a typical problem when JVM quits abnormally, like OutOfMemoryError during a test. + SuiteResult sr = new SuiteResult(reportFile.getName(), "", ""); + sr.addCase(new CaseResult(sr,"","Test report file "+reportFile.getAbsolutePath()+" was length 0")); + add(sr); + } else { + parse(reportFile); + } + } + private void add(SuiteResult sr) { for (SuiteResult s : suites) { // JENKINS-12457: If a testsuite is distributed over multiple files, merge it into a single SuiteResult: @@ -588,6 +635,5 @@ public final class TestResult extends MetaTabulatedResult { } private static final long serialVersionUID = 1L; - private static final boolean checkTimestamps = true; // TODO: change to System.getProperty } diff --git a/maven-plugin/src/main/java/hudson/maven/Maven3Builder.java b/maven-plugin/src/main/java/hudson/maven/Maven3Builder.java index cd4d9f0ae871e96e1e044bb9eecb3b915d3c86b3..6e18914e49bb9a18fa20ff8730a4f1fbffced97c 100644 --- a/maven-plugin/src/main/java/hudson/maven/Maven3Builder.java +++ b/maven-plugin/src/main/java/hudson/maven/Maven3Builder.java @@ -218,8 +218,10 @@ public class Maven3Builder extends AbstractMavenBuilder implements DelegatingCal return reporters.get( new ModuleName( mavenProject ) ); } - private void initMojoStartTime( MavenProject mavenProject) { - this.currentMojoStartPerModuleName.put( new ModuleName( mavenProject), System.currentTimeMillis()); + private long initMojoStartTime( MavenProject mavenProject) { + long mojoStartTime = System.currentTimeMillis(); + this.currentMojoStartPerModuleName.put( new ModuleName( mavenProject), mojoStartTime); + return mojoStartTime; } private Long getMojoStartTime(MavenProject mavenProject) { @@ -395,10 +397,10 @@ public class Maven3Builder extends AbstractMavenBuilder implements DelegatingCal } private void recordMojoStarted(ExecutionEvent event) { - initMojoStartTime( event.getProject() ); + long startTime = initMojoStartTime( event.getProject() ); MavenProject mavenProject = event.getProject(); - MojoInfo mojoInfo = new MojoInfo(event); + MojoInfo mojoInfo = new MojoInfo(event,startTime); List mavenReporters = getMavenReporters( mavenProject ); @@ -426,7 +428,7 @@ public class Maven3Builder extends AbstractMavenBuilder implements DelegatingCal private void recordMojoEnded(ExecutionEvent event, Exception problem) { MavenProject mavenProject = event.getProject(); - MojoInfo mojoInfo = new MojoInfo(event); + MojoInfo mojoInfo = new MojoInfo(event,getMojoStartTime(event.getProject())); recordExecutionTime(event,mojoInfo); diff --git a/maven-plugin/src/main/java/hudson/maven/MavenBuilder.java b/maven-plugin/src/main/java/hudson/maven/MavenBuilder.java index 8a60f7c2fb16701e32a4f34ddeb9d168eced5b57..72a60954d924319da01cbef3eb27924c755df93c 100644 --- a/maven-plugin/src/main/java/hudson/maven/MavenBuilder.java +++ b/maven-plugin/src/main/java/hudson/maven/MavenBuilder.java @@ -43,6 +43,7 @@ import java.text.NumberFormat; import java.util.Collection; import java.util.List; import java.util.Map; +import java.util.concurrent.ConcurrentHashMap; import java.util.concurrent.atomic.AtomicBoolean; import org.apache.maven.BuildFailureException; @@ -275,6 +276,7 @@ public abstract class MavenBuilder extends AbstractMavenBuilder implements Deleg private final MavenBuilder listener; private final AtomicBoolean hasTestFailures = new AtomicBoolean(); + private final Map currentMojoStartPerModuleName = new ConcurrentHashMap(); /** * Number of total nanoseconds {@link MavenBuilder} spent. @@ -284,6 +286,16 @@ public abstract class MavenBuilder extends AbstractMavenBuilder implements Deleg public Adapter(MavenBuilder listener) { this.listener = listener; } + + private long initMojoStartTime( MavenProject mavenProject) { + long mojoStartTime = System.currentTimeMillis(); + this.currentMojoStartPerModuleName.put( new ModuleName( mavenProject), mojoStartTime); + return mojoStartTime; + } + + private Long getMojoStartTime(MavenProject mavenProject) { + return currentMojoStartPerModuleName.get( new ModuleName(mavenProject) ); + } public void preBuild(MavenSession session, ReactorManager rm, EventDispatcher dispatcher) throws BuildFailureException, LifecycleExecutionException, IOException, InterruptedException { long startTime = System.nanoTime(); @@ -312,13 +324,14 @@ public abstract class MavenBuilder extends AbstractMavenBuilder implements Deleg fireEnterModule(project); } - listener.preExecute(project, new MojoInfo(exec, mojo, mergedConfig, eval)); + long mojoStartTime = initMojoStartTime(project); + listener.preExecute(project, new MojoInfo(exec, mojo, mergedConfig, eval, mojoStartTime)); overheadTime += System.nanoTime()-startTime; } public void postExecute(MavenProject project, MojoExecution exec, Mojo mojo, PlexusConfiguration mergedConfig, ExpressionEvaluator eval, Exception exception) throws IOException, InterruptedException { long startTime = System.nanoTime(); - listener.postExecute(project, new MojoInfo(exec, mojo, mergedConfig, eval),exception); + listener.postExecute(project, new MojoInfo(exec, mojo, mergedConfig, eval, getMojoStartTime(project)),exception); if(listener.hasBuildFailures()) hasTestFailures.compareAndSet(false, true); overheadTime += System.nanoTime()-startTime; @@ -326,7 +339,8 @@ public abstract class MavenBuilder extends AbstractMavenBuilder implements Deleg public void onReportGenerated(MavenReport report, MojoExecution mojoExecution, PlexusConfiguration mergedConfig, ExpressionEvaluator eval) throws IOException, InterruptedException { long startTime = System.nanoTime(); - listener.onReportGenerated(lastModule,new MavenReportInfo(mojoExecution,report,mergedConfig,eval)); + listener.onReportGenerated(lastModule,new MavenReportInfo(mojoExecution,report,mergedConfig,eval, + getMojoStartTime(lastModule))); overheadTime += System.nanoTime()-startTime; } diff --git a/maven-plugin/src/main/java/hudson/maven/MavenReportInfo.java b/maven-plugin/src/main/java/hudson/maven/MavenReportInfo.java index d31da6c372e6652a41da77c4e3c0f125957c728d..782a9a2a4ca4dd6bc4a01b4d3b813e42b6aa5b8b 100644 --- a/maven-plugin/src/main/java/hudson/maven/MavenReportInfo.java +++ b/maven-plugin/src/main/java/hudson/maven/MavenReportInfo.java @@ -49,8 +49,9 @@ public final class MavenReportInfo extends MojoInfo { */ public final MavenReport report; - public MavenReportInfo(MojoExecution mojoExecution, MavenReport mojo, PlexusConfiguration configuration, ExpressionEvaluator expressionEvaluator) { - super(mojoExecution, (Mojo)mojo, configuration, expressionEvaluator); + public MavenReportInfo(MojoExecution mojoExecution, MavenReport mojo, PlexusConfiguration configuration, ExpressionEvaluator expressionEvaluator, + long mojoStartTime) { + super(mojoExecution, (Mojo)mojo, configuration, expressionEvaluator,mojoStartTime); this.report = mojo; } } diff --git a/maven-plugin/src/main/java/hudson/maven/MojoInfo.java b/maven-plugin/src/main/java/hudson/maven/MojoInfo.java index 0097013958e8132c1989677eb74001ccf2cfccd1..59dffc0670951fe3bb1781020e4914cc72031ad8 100644 --- a/maven-plugin/src/main/java/hudson/maven/MojoInfo.java +++ b/maven-plugin/src/main/java/hudson/maven/MojoInfo.java @@ -103,7 +103,10 @@ public class MojoInfo { */ private final ConverterLookup converterLookup = new DefaultConverterLookup(); - public MojoInfo(MojoExecution mojoExecution, Mojo mojo, PlexusConfiguration configuration, ExpressionEvaluator expressionEvaluator) { + private long startTime; + + public MojoInfo(MojoExecution mojoExecution, Mojo mojo, PlexusConfiguration configuration, ExpressionEvaluator expressionEvaluator, + long startTime) { // in Maven3 there's no easy way to get the Mojo instance that's being executed, // so we just can't pass it in. if (mojo==null) mojo = new Maven3ProvidesNoAccessToMojo(); @@ -112,12 +115,13 @@ public class MojoInfo { this.configuration = configuration; this.expressionEvaluator = expressionEvaluator; this.pluginName = new PluginName(mojoExecution.getMojoDescriptor().getPluginDescriptor()); + this.startTime = startTime; } - public MojoInfo(ExecutionEvent event) { + public MojoInfo(ExecutionEvent event, long startTime) { this(event.getMojoExecution(), null, new XmlPlexusConfiguration( event.getMojoExecution().getConfiguration() ), - new PluginParameterExpressionEvaluator( event.getSession(), event.getMojoExecution() )); + new PluginParameterExpressionEvaluator( event.getSession(), event.getMojoExecution() ), startTime); } /** @@ -148,7 +152,7 @@ public class MojoInfo { * the configuration in POM is syntactically incorrect. */ public T getConfigurationValue(String configName, Class type) throws ComponentConfigurationException { - PlexusConfiguration child = configuration.getChild(configName); + PlexusConfiguration child = configuration.getChild(configName,false); if(child==null) return null; // no such config final ClassLoader cl; @@ -278,4 +282,8 @@ public class MojoInfo { throw new UnsupportedOperationException(); } } + + public long getStartTime() { + return this.startTime; + } } diff --git a/maven-plugin/src/main/java/hudson/maven/reporters/SurefireArchiver.java b/maven-plugin/src/main/java/hudson/maven/reporters/SurefireArchiver.java index 9e8d918a34d924bb1617811a908a590f0fb7bf4b..80b7a24e7c7b8eeef3bf100b1d1aba6423ed7287 100644 --- a/maven-plugin/src/main/java/hudson/maven/reporters/SurefireArchiver.java +++ b/maven-plugin/src/main/java/hudson/maven/reporters/SurefireArchiver.java @@ -25,7 +25,6 @@ package hudson.maven.reporters; import hudson.Extension; import hudson.Launcher; -import hudson.Util; import hudson.maven.Maven3Builder; import hudson.maven.MavenBuild; import hudson.maven.MavenBuildInformation; @@ -47,6 +46,7 @@ import java.io.File; import java.io.IOException; import java.util.Collection; import java.util.Collections; +import java.util.Iterator; import java.util.List; import java.util.ListIterator; import java.util.concurrent.ConcurrentHashMap; @@ -55,26 +55,29 @@ import java.util.concurrent.atomic.AtomicBoolean; import org.apache.maven.plugin.MojoFailureException; import org.apache.maven.project.MavenProject; -import org.apache.tools.ant.DirectoryScanner; -import org.apache.tools.ant.types.FileSet; import org.codehaus.plexus.component.configurator.ComponentConfigurationException; import org.codehaus.plexus.configuration.xml.XmlPlexusConfiguration; import org.codehaus.plexus.util.xml.Xpp3Dom; +import com.google.common.base.Function; +import com.google.common.base.Predicate; +import com.google.common.collect.Iterables; +import com.google.common.collect.Iterators; + /** * Records the surefire test result. * @author Kohsuke Kawaguchi + * @author Christoph Kutzinski */ public class SurefireArchiver extends TestFailureDetector { private transient TestResult result; private final AtomicBoolean hasTestFailures = new AtomicBoolean(); /** - * Store the filesets here as we want to track ignores between multiple runs of this class
- * Note: Because this class can be run with different mojo goals with different path settings, - * we track multiple {@link FileSet}s for each encountered reportsDir + * Store result files already parsed, so we don't parse them again, + * if a later running mojo specifies the same reports directory. */ - private transient ConcurrentMap fileSets = new ConcurrentHashMap(); + private transient ConcurrentMap parsedFiles = new ConcurrentHashMap(); @Override public boolean hasTestFailures() { @@ -83,25 +86,27 @@ public class SurefireArchiver extends TestFailureDetector { public boolean preExecute(MavenBuildProxy build, MavenProject pom, MojoInfo mojo, BuildListener listener) throws InterruptedException, IOException { if (isTestMojo(mojo)) { - if (!isSoapUiMojo(mojo)) { - // tell surefire:test to keep going even if there was a failure, - // so that we can record this as yellow. - // note that because of the way Maven works, just updating system property at this point is too late - XmlPlexusConfiguration c = (XmlPlexusConfiguration) mojo.configuration.getChild("testFailureIgnore"); - if(c!=null && c.getValue() != null && c.getValue().equals("${maven.test.failure.ignore}") && System.getProperty("maven.test.failure.ignore")==null) { - if (build.getMavenBuildInformation().isMaven3OrLater()) { - String fieldName = "testFailureIgnore"; - if (mojo.mojoExecution.getConfiguration().getChild( fieldName ) != null) { - mojo.mojoExecution.getConfiguration().getChild( fieldName ).setValue( Boolean.TRUE.toString() ); - } else { - Xpp3Dom child = new Xpp3Dom( fieldName ); - child.setValue( Boolean.TRUE.toString() ); - mojo.mojoExecution.getConfiguration().addChild( child ); - } - + // tell test mojo to keep going even if there was a failure, + // so that we can record this as yellow. + // note that because of the way Maven works, just updating system property at this point is too late + + // Many test plugins have - as surefire - a configuration key 'testFailureIgnore' which defaults to + // ${maven.test.failure.ignore}, so just try that one and change value to true, + // if it's still at that default: + XmlPlexusConfiguration c = (XmlPlexusConfiguration) mojo.configuration.getChild("testFailureIgnore"); + if(c!=null && c.getValue() != null && c.getValue().equals("${maven.test.failure.ignore}") && System.getProperty("maven.test.failure.ignore")==null) { + if (build.getMavenBuildInformation().isMaven3OrLater()) { + String fieldName = "testFailureIgnore"; + if (mojo.mojoExecution.getConfiguration().getChild( fieldName ) != null) { + mojo.mojoExecution.getConfiguration().getChild( fieldName ).setValue( Boolean.TRUE.toString() ); } else { - c.setValue(Boolean.TRUE.toString()); + Xpp3Dom child = new Xpp3Dom( fieldName ); + child.setValue( Boolean.TRUE.toString() ); + mojo.mojoExecution.getConfiguration().addChild( child ); } + + } else { + c.setValue(Boolean.TRUE.toString()); } } } @@ -109,41 +114,45 @@ public class SurefireArchiver extends TestFailureDetector { } public boolean postExecute(MavenBuildProxy build, MavenProject pom, MojoInfo mojo, final BuildListener listener, Throwable error) throws InterruptedException, IOException { - if (!isTestMojo(mojo)) return true; + TestMojo testMojo = TestMojo.lookup(mojo); + if (testMojo == null) return true; listener.getLogger().println(Messages.SurefireArchiver_Recording()); - File reportsDir; - if (isSurefireOrFailsafeMojo(mojo)) { - try { - reportsDir = mojo.getConfigurationValue("reportsDirectory", File.class); - } catch (ComponentConfigurationException e) { - e.printStackTrace(listener.fatalError(Messages.SurefireArchiver_NoReportsDir())); - build.setResult(Result.FAILURE); - return true; - } - } - else { - reportsDir = new File(pom.getBasedir(), "target/surefire-reports"); + Iterable fileSet; + + try { + fileSet = testMojo.getReportFiles(pom, mojo); + } catch (ComponentConfigurationException e) { + e.printStackTrace(listener.fatalError(Messages.SurefireArchiver_NoReportsDir())); + build.setResult(Result.FAILURE); + return true; } - - if(reportsDir.exists()) { - // surefire:test just skips itself when the current project is not a java project - + + if(fileSet != null) { synchronized (build) { - FileSet fileSet = getFileSet(reportsDir); - DirectoryScanner ds = fileSet.getDirectoryScanner(); + if(result==null) result = new TestResult(); - if(ds.getIncludedFilesCount()==0) - // no test in this module + // filter all the already parsed files: + fileSet = Iterables.filter(fileSet, new Predicate() { + @Override + public boolean apply(File input) { + return !parsedFiles.containsKey(input); + } + }); + + if (!fileSet.iterator().hasNext()) return true; - String[] reportFiles = ds.getIncludedFiles(); - rememberCheckedFiles(reportsDir, reportFiles); - - if(result==null) result = new TestResult(); - result.parse(System.currentTimeMillis() - build.getMilliSecsSinceBuildStart(), reportsDir, reportFiles); + result.parse(System.currentTimeMillis() - build.getMilliSecsSinceBuildStart(), fileSet); + // TODO kutzi: the following is a 'more correct' way to get the reports associated to a mojo, + // but needs more testing +// Iterable reportFilesFiltered = getFilesBetween(reportsDir, reportFiles, mojo.getStartTime(), System.currentTimeMillis()); +// result.parse(reportFilesFiltered); + + + rememberCheckedFiles(fileSet); // final reference in order to serialize it: final TestResult r = result; @@ -199,33 +208,13 @@ public class SurefireArchiver extends TestFailureDetector { } } - /** - * Returns the appropriate FileSet for the selected baseDir - * @param baseDir - * @return - */ - FileSet getFileSet(File baseDir) { - FileSet fs = fileSets.get(baseDir); - if (fs == null) { - fs = Util.createFileSet(baseDir, "*.xml","testng-results.xml,testng-failed.xml"); - FileSet previous = fileSets.putIfAbsent(baseDir, fs); - if (previous != null) { - return previous; - } - } - - return fs; - } - /** * Add checked files to the exclude list of the fileSet */ - private void rememberCheckedFiles(File baseDir, String[] reportFiles) { - FileSet fileSet = getFileSet(baseDir); - - for (String file : reportFiles) { - fileSet.createExclude().setName(file); - } + private void rememberCheckedFiles(Iterable fileSet) { + for (File f : fileSet) { + this.parsedFiles.put(f, f); + } } /** @@ -244,6 +233,65 @@ public class SurefireArchiver extends TestFailureDetector { } } +// private static Iterable getFilesBetween(final File reportsDir, +// final String[] reportFiles, final long from, final long to) { +// return new FilteredReportsFileIterable(reportsDir, reportFiles, from, to); +// } + + /** + * Provides an {@link Iterable} view on the reports files while filtering out all files + * which don't have a lastModified time in between from and to. + */ + static class FilteredReportsFileIterable implements Iterable { + private final File reportsDir; + private final String[] reportFiles; + private final long from; + private final long to; + + FilteredReportsFileIterable(File reportsDir, + String[] reportFiles, long from, long to) { + this.reportsDir = reportsDir; + this.reportFiles = reportFiles; + + // FAT filesystems have a max resolution of 2 seconds so we need to subtract/add 2 seconds to + // the range borders. + // All other fs should have a equal or better precision + this.from = from - 2000; + this.to = to + 2000; + } + + @Override + public Iterator iterator() { + + Predicate fileWithinFromAndTo = new Predicate() { + @Override + public boolean apply(File file) { + long lastModified = file.lastModified(); + if (lastModified>=from && lastModified<=to) { + return true; + } + return false; + } + }; + + return Iterators.filter( + Iterators.transform( + Iterators.forArray(reportFiles), + new Function() { + @Override + public File apply(String file) { + return getFile(reportsDir,file); + } + }), + fileWithinFromAndTo); + } + + // here for mocking purposes: + File getFile(File parent, String child) { + return new File(parent,child); + } + } + /** * Part of the serialization data attached to {@link MavenBuild}. */ @@ -253,80 +301,21 @@ public class SurefireArchiver extends TestFailureDetector { } } - private boolean isTestMojo(MojoInfo mojo) { - if ((!mojo.is("com.sun.maven", "maven-junit-plugin", "test")) - && (!mojo.is("org.sonatype.flexmojos", "flexmojos-maven-plugin", "test-run")) - && (!mojo.is("org.eclipse.tycho", "tycho-surefire-plugin", "test")) - && (!mojo.is("org.sonatype.tycho", "maven-osgi-test-plugin", "test")) - && (!mojo.is("org.codehaus.mojo", "gwt-maven-plugin", "test")) - && (!isAndroidMojo(mojo)) - && (!isSurefireOrFailsafeMojo(mojo)) - && (!isSoapUiMojo(mojo))) - return false; + boolean isTestMojo(MojoInfo mojo) { + + TestMojo testMojo = TestMojo.lookup(mojo); + if (testMojo == null) + return false; + try { - if (isSurefireOrFailsafeMojo(mojo)) { - Boolean skip = mojo.getConfigurationValue("skip", Boolean.class); + // most test plugins have at least on of the test-skip properties: + String[] skipProperties = {"skip", "skipExec", "skipTests", "skipTest"}; + for (String skipProperty : skipProperties) { + Boolean skip = mojo.getConfigurationValue(skipProperty, Boolean.class); if (((skip != null) && (skip))) { return false; } - - if (mojo.pluginName.version.compareTo("2.3") >= 0) { - Boolean skipExec = mojo.getConfigurationValue("skipExec", Boolean.class); - - if (((skipExec != null) && (skipExec))) { - return false; - } - } - - if (mojo.pluginName.version.compareTo("2.4") >= 0) { - Boolean skipTests = mojo.getConfigurationValue("skipTests", Boolean.class); - - if (((skipTests != null) && (skipTests))) { - return false; - } - } - } - else if (mojo.is("com.sun.maven", "maven-junit-plugin", "test")) { - Boolean skipTests = mojo.getConfigurationValue("skipTests", Boolean.class); - - if (((skipTests != null) && (skipTests))) { - return false; - } - } - else if (mojo.is("org.sonatype.flexmojos", "flexmojos-maven-plugin", "test-run")) { - Boolean skipTests = mojo.getConfigurationValue("skipTest", Boolean.class); - if (((skipTests != null) && (skipTests))) { - return false; - } - } else if (mojo.is("org.sonatype.tycho", "maven-osgi-test-plugin", "test")) { - Boolean skipTests = mojo.getConfigurationValue("skipTest", Boolean.class); - if (((skipTests != null) && (skipTests))) { - return false; - } - } else if (mojo.is("org.eclipse.tycho", "tycho-surefire-plugin", "test")) { - Boolean skipTests = mojo.getConfigurationValue("skipTest", Boolean.class); - if (((skipTests != null) && (skipTests))) { - return false; - } - } else if (isAndroidMojo(mojo)) { - if (mojo.pluginName.version.compareTo("3.0.0-alpha-6") < 0) { - // Earlier versions do not support tests - return false; - } else { - Boolean skipTests = mojo.getConfigurationValue("skipTests", Boolean.class); - if (((skipTests != null) && (skipTests))) { - return false; - } - } - } else if (mojo.is("org.codehaus.mojo", "gwt-maven-plugin", "test") && mojo.pluginName.version.compareTo("1.2") < 0) { - // gwt-maven-plugin < 1.2 does not implement required Surefire option - return false; - } else if (isSoapUiMojo(mojo)) { - Boolean skipTests = mojo.getConfigurationValue("skip", Boolean.class); - if (((skipTests != null) && (skipTests))) { - return false; - } } } catch (ComponentConfigurationException e) { return false; @@ -334,26 +323,11 @@ public class SurefireArchiver extends TestFailureDetector { return true; } - - private boolean isAndroidMojo(MojoInfo mojo) { - return mojo.is("com.jayway.maven.plugins.android.generation2", "maven-android-plugin", "internal-integration-test") - || mojo.is("com.jayway.maven.plugins.android.generation2", "android-maven-plugin", "internal-integration-test"); - } - - private boolean isSurefireOrFailsafeMojo(MojoInfo mojo) { - return mojo.is("org.apache.maven.plugins", "maven-surefire-plugin", "test") - || mojo.is("org.apache.maven.plugins", "maven-failsafe-plugin", "verify"); - } - - private boolean isSoapUiMojo(MojoInfo mojo) { - return mojo.is("eviware", "maven-soapui-plugin", "test") - || mojo.is("eviware", "maven-soapui-pro-plugin", "test"); - } // I'm not sure if SurefireArchiver is actually ever (de-)serialized, // but just to be sure, set fileSets here protected Object readResolve() { - fileSets = new ConcurrentHashMap(); + parsedFiles = new ConcurrentHashMap(); return this; } diff --git a/maven-plugin/src/main/java/hudson/maven/reporters/TestMojo.java b/maven-plugin/src/main/java/hudson/maven/reporters/TestMojo.java new file mode 100644 index 0000000000000000000000000000000000000000..562ee351aaf89937e1f92c207fd91043578eb4d8 --- /dev/null +++ b/maven-plugin/src/main/java/hudson/maven/reporters/TestMojo.java @@ -0,0 +1,223 @@ +package hudson.maven.reporters; + +import hudson.Util; +import hudson.maven.MojoInfo; + +import java.io.File; +import java.util.Collection; +import java.util.Collections; +import java.util.Iterator; + +import org.apache.maven.project.MavenProject; +import org.apache.tools.ant.types.FileSet; +import org.codehaus.plexus.component.configurator.ComponentConfigurationException; + +import com.google.common.base.Function; +import com.google.common.collect.Iterators; + +/** + * Description of a mojo which can run tests. + * + * @author kutzi + */ +enum TestMojo { + + /** + * Fallback to this if we have no exact match + */ + FALLBACK("","","","reportsDirectory") { + @Override + protected boolean is(String artifactId, String groupId, String goal) { + // never match anything implicitly + return false; + } + }, + + MAVEN_SUREFIRE("org.apache.maven.plugins", "maven-surefire-plugin","test","reportsDirectory"), + MAVEN_FAILSAFE("org.apache.maven.plugins", "maven-failsafe-plugin", "verify","reportsDirectory"), + + MAVEN_JUNIT("com.sun.maven", "maven-junit-plugin", "test","reportsDirectory"), + FLEXMOJOS("org.sonatype.flexmojos", "flexmojos-maven-plugin", "test-run",null), + + MAVEN_OSGI_TEST("org.sonatype.tycho", "maven-osgi-test-plugin", "test","reportsDirectory"), + TYCHO_SUREFIRE("org.eclipse.tycho", "tycho-surefire-plugin", "test","reportsDirectory"), + + MAVEN_ANDROID_PLUGIN("com.jayway.maven.plugins.android.generation2", "maven-android-plugin", + "internal-integration-test",null,"3.0.0-alpha-6"), + ANDROID_MAVEN_PLUGIN("com.jayway.maven.plugins.android.generation2", "android-maven-plugin", + "internal-integration-test",null,"3.0.0-alpha-6"), + + GWT_MAVEN_PLUGIN("org.codehaus.mojo", "gwt-maven-plugin", "test","reportsDirectory","1.2"), + + MAVEN_SOAPUI_PLUGIN("eviware", "maven-soapui-plugin", "test", "outputFolder"), + MAVEN_SOAPUI_PRO_PLUGIN("eviware", "maven-soapui-pro-plugin", "test","outputFolder"), + + JASMINE("com.github.searls","jasmine-maven-plugin","test",null) { + @Override + public Collection getReportFiles(MavenProject pom,MojoInfo mojo) + throws ComponentConfigurationException { + // jasmine just creates a single JUnit result file + File reportsDir = mojo.getConfigurationValue("jasmineTargetDir", File.class); + String junitFileName = mojo.getConfigurationValue("junitXmlReportFileName", String.class); + + return Collections.singleton(new File(reportsDir,junitFileName)); + } + }, + TOOLKIT_RESOLVER_PLUGIN("org.terracotta.maven.plugins", "toolkit-resolver-plugin", "toolkit-resolve-test","reportsDirectory"); + + private String reportDirectoryConfigKey; + private Key key; + private String minimalRequiredVersion; + + private TestMojo(String artifactId, String groupId, String goal, + String reportDirectoryConfigKey) { + this.key = new Key(artifactId,groupId,goal); + this.reportDirectoryConfigKey = reportDirectoryConfigKey; + } + + private TestMojo(String artifactId, String groupId, String goal, + String reportDirectoryConfigKey,String minimalRequiredVersion) { + this.key = new Key(artifactId,groupId,goal); + this.reportDirectoryConfigKey = reportDirectoryConfigKey; + this.minimalRequiredVersion = minimalRequiredVersion; + } + + public Key getKey() { + return this.key; + } + + /** + * Says if this mojo can run tests. + * Can e.g. return false if the version of the plugin is too old to create output in JUnit format. + */ + public boolean canRunTests(MojoInfo mojo) { + if (this.minimalRequiredVersion == null) { + return true; + } + + return mojo.pluginName.version.compareTo(this.minimalRequiredVersion) >= 0; + } + + public Iterable getReportFiles(MavenProject pom, MojoInfo mojo) throws ComponentConfigurationException { + if (this.reportDirectoryConfigKey != null) { + File reportsDir = mojo.getConfigurationValue(this.reportDirectoryConfigKey, File.class); + if (reportsDir.exists()) { + return getReportFiles(reportsDir, getFileSet(reportsDir)); + } + + } + + // some plugins just default to this: + File reportsDir = new File(pom.getBasedir(), pom.getBuild().getDirectory()+File.separator+"surefire-reports"); + if (reportsDir.exists()) { + return getReportFiles(reportsDir, getFileSet(reportsDir)); + } + + return null; + } + + private Iterable getReportFiles(final File baseDir, FileSet set) { + final String[] includedFiles = set.getDirectoryScanner().getIncludedFiles(); + + return new Iterable() { + public Iterator iterator() { + return Iterators.transform( + Iterators.forArray(includedFiles), + new Function() { + @Override + public File apply(String file) { + return new File(baseDir,file); + } + }); + } + }; + } + + /** + * Returns the appropriate FileSet for the selected baseDir + * @param baseDir + * @return + */ + private FileSet getFileSet(File baseDir) { + return Util.createFileSet(baseDir, "*.xml","testng-results.xml,testng-failed.xml"); + } + + protected boolean is(String artifactId, String groupId, String goal) { + return key.artifactId.equals(artifactId) && key.groupId.equals(groupId) + && key.goal.equals(goal); + } + + public static TestMojo lookup(String artifactId, String groupId, String goal) { + for (TestMojo mojo : values()) { + if (mojo.is(artifactId,groupId,goal)) { + return mojo; + } + } + + if (goal.equals("test") || goal.equals("test-run")) { + return FALLBACK; + } + + return null; + } + + public static TestMojo lookup(MojoInfo mojo) { + TestMojo testMojo = lookup(mojo.pluginName.groupId, mojo.pluginName.artifactId, mojo.getGoal()); + if (testMojo != null && testMojo.canRunTests(mojo)) { + return testMojo; + } + return null; + } + + static class Key { + private String artifactId; + private String groupId; + private String goal; + + public Key(String artifactId, String groupId, String goal) { + super(); + this.artifactId = artifactId; + this.groupId = groupId; + this.goal = goal; + } + + @Override + public int hashCode() { + final int prime = 31; + int result = 1; + result = prime * result + + ((artifactId == null) ? 0 : artifactId.hashCode()); + result = prime * result + ((goal == null) ? 0 : goal.hashCode()); + result = prime * result + + ((groupId == null) ? 0 : groupId.hashCode()); + return result; + } + @Override + public boolean equals(Object obj) { + if (this == obj) + return true; + if (obj == null) + return false; + if (getClass() != obj.getClass()) + return false; + Key other = (Key) obj; + if (artifactId == null) { + if (other.artifactId != null) + return false; + } else if (!artifactId.equals(other.artifactId)) + return false; + if (goal == null) { + if (other.goal != null) + return false; + } else if (!goal.equals(other.goal)) + return false; + if (groupId == null) { + if (other.groupId != null) + return false; + } else if (!groupId.equals(other.groupId)) + return false; + return true; + } + } + +} diff --git a/maven-plugin/src/test/java/hudson/maven/ExecutedMojoTest.java b/maven-plugin/src/test/java/hudson/maven/ExecutedMojoTest.java index 0f2fd41df8f98a0ab834972471ae7c63a8108c77..4505e6ec7efd985457e6a95b2ad6e52a3382e4f8 100644 --- a/maven-plugin/src/test/java/hudson/maven/ExecutedMojoTest.java +++ b/maven-plugin/src/test/java/hudson/maven/ExecutedMojoTest.java @@ -53,7 +53,7 @@ public class ExecutedMojoTest { // Faking JUnit's Assert to be the plugin class this.mojoDescriptor.setImplementation(Assert.class.getName()); MojoExecution execution = new MojoExecution(this.mojoDescriptor); - MojoInfo info = new MojoInfo(execution, null, null, null); + MojoInfo info = new MojoInfo(execution, null, null, null, -1); ExecutedMojo executedMojo = new ExecutedMojo(info, 1L); @@ -66,7 +66,7 @@ public class ExecutedMojoTest { // Faking this class as the mojo impl: this.mojoDescriptor.setImplementation(getClass().getName()); MojoExecution execution = new MojoExecution(this.mojoDescriptor); - MojoInfo info = new MojoInfo(execution, null, null, null); + MojoInfo info = new MojoInfo(execution, null, null, null, -1); ExecutedMojo executedMojo = new ExecutedMojo(info, 1L); diff --git a/maven-plugin/src/test/java/hudson/maven/MojoInfoBuilder.java b/maven-plugin/src/test/java/hudson/maven/MojoInfoBuilder.java new file mode 100644 index 0000000000000000000000000000000000000000..be59ee773bdaefb48ffaf26a391d8757484f2c60 --- /dev/null +++ b/maven-plugin/src/test/java/hudson/maven/MojoInfoBuilder.java @@ -0,0 +1,91 @@ +package hudson.maven; + +import hudson.maven.MojoInfo; + +import java.io.File; +import java.util.HashMap; +import java.util.Map; + +import org.apache.maven.plugin.MojoExecution; +import org.apache.maven.plugin.descriptor.MojoDescriptor; +import org.apache.maven.plugin.descriptor.PluginDescriptor; +import org.codehaus.plexus.component.configurator.expression.ExpressionEvaluator; +import org.codehaus.plexus.configuration.DefaultPlexusConfiguration; +import org.codehaus.plexus.configuration.PlexusConfiguration; + +public class MojoInfoBuilder { + + private String groupId; + private String artifactId; + private String goalName; + private String version = "1.0"; + private Map configValues = new HashMap(); + private long startTime = System.currentTimeMillis(); + + public static MojoInfoBuilder mojoBuilder(String groupId, String artifactId, String goalName) { + return new MojoInfoBuilder(groupId, artifactId, goalName); + } + + private MojoInfoBuilder(String groupId, String artifactId, String goalName) { + this.groupId = groupId; + this.artifactId = artifactId; + this.goalName = goalName; + } + + public MojoInfoBuilder copy() { + MojoInfoBuilder copy = new MojoInfoBuilder(this.groupId, this.artifactId, this.goalName) + .version(this.version); + copy.configValues.putAll(this.configValues); + return copy; + } + + public MojoInfoBuilder version(String version) { + this.version = version; + return this; + } + + public MojoInfoBuilder startTime(long startTime) { + this.startTime = startTime; + return this; + } + + public MojoInfoBuilder configValue(String key,String value) { + configValues.put(key, value); + return this; + } + + public MojoInfo build() { + PluginDescriptor pluginDescriptor = new PluginDescriptor(); + pluginDescriptor.setGroupId(groupId); + pluginDescriptor.setArtifactId(artifactId); + pluginDescriptor.setVersion(version); + + MojoDescriptor mojoDescriptor = new MojoDescriptor(); + mojoDescriptor.setPluginDescriptor(pluginDescriptor); + mojoDescriptor.setGoal(goalName); + + MojoExecution mojoExecution = new MojoExecution(mojoDescriptor); + + PlexusConfiguration configuration = new DefaultPlexusConfiguration("configuration"); + for (Map.Entry e : this.configValues.entrySet()) { + configuration.addChild(e.getKey(),e.getValue()); + } + + ExpressionEvaluator evaluator = new ExpressionEvaluator() { + @Override + public Object evaluate(String expression) { + return expression; + } + + @Override + public File alignToBaseDirectory(File file) { + return file; + } + }; + + MojoInfo info = new MojoInfo(mojoExecution, null, configuration, evaluator, startTime); + return info; + } + + +} diff --git a/maven-plugin/src/test/java/hudson/maven/reporters/SurefireArchiverDetectTestMojosTest.java b/maven-plugin/src/test/java/hudson/maven/reporters/SurefireArchiverDetectTestMojosTest.java new file mode 100644 index 0000000000000000000000000000000000000000..7d5f70cfd499e42b5edc4bde44bbed73404d928d --- /dev/null +++ b/maven-plugin/src/test/java/hudson/maven/reporters/SurefireArchiverDetectTestMojosTest.java @@ -0,0 +1,182 @@ +package hudson.maven.reporters; + +import static hudson.maven.MojoInfoBuilder.mojoBuilder; +import static org.junit.Assert.assertFalse; +import static org.junit.Assert.assertTrue; +import hudson.maven.MojoInfo; +import hudson.maven.MojoInfoBuilder; + +import org.junit.Before; +import org.junit.Test; + +/** + * Regression test for the detection of test mojos in {@link SurefireArchiver}. + * + * @author kutzi + */ +public class SurefireArchiverDetectTestMojosTest { + + private SurefireArchiver surefireArchiver; + + @Before + public void before() { + this.surefireArchiver = new SurefireArchiver(); + } + + @Test + public void shouldDetectMavenSurefire() { + MojoInfo mojo = mojoBuilder("org.apache.maven.plugins", "maven-surefire-plugin", "test").build(); + assertTrue(this.surefireArchiver.isTestMojo(mojo)); + } + + @Test + public void shouldDetectMavenFailsafe() { + MojoInfo mojo = mojoBuilder("org.apache.maven.plugins", "maven-failsafe-plugin", "verify").build(); + assertTrue(this.surefireArchiver.isTestMojo(mojo)); + } + + @Test + public void shouldDetectMavenSurefireSkip() { + MojoInfoBuilder builder = mojoBuilder("org.apache.maven.plugins", "maven-surefire-plugin", "test"); + MojoInfo mojo = builder.copy() + .configValue("skip", "true").build(); + assertFalse(this.surefireArchiver.isTestMojo(mojo)); + + mojo = builder.copy() + .version("2.4") + .configValue("skipTests", "true").build(); + assertFalse(this.surefireArchiver.isTestMojo(mojo)); + + mojo = builder.copy() + .version("2.3") + .configValue("skipExec", "true").build(); + assertFalse(this.surefireArchiver.isTestMojo(mojo)); + + // That's not a valid skip property: + mojo = builder.copy() + .configValue("skip--Exec", "true").build(); + assertTrue(this.surefireArchiver.isTestMojo(mojo)); + } + + @Test + public void shouldDetectMavenJunitPlugin() { + MojoInfoBuilder builder = mojoBuilder("com.sun.maven", "maven-junit-plugin", "test"); + MojoInfo mojo = builder.build(); + assertTrue(this.surefireArchiver.isTestMojo(mojo)); + + mojo = builder.copy() + .configValue("skipTests", "true").build(); + assertFalse(this.surefireArchiver.isTestMojo(mojo)); + } + + @Test + public void shouldDetectFlexMojoMavenPlugin() { + MojoInfoBuilder builder = mojoBuilder("org.sonatype.flexmojos", "flexmojos-maven-plugin", "test-run"); + MojoInfo mojo = builder.build(); + assertTrue(this.surefireArchiver.isTestMojo(mojo)); + + mojo = builder.copy() + .configValue("skipTest", "true").build(); + assertFalse(this.surefireArchiver.isTestMojo(mojo)); + } + + @Test + public void shouldDetectOsgiTestPlugin() { + MojoInfoBuilder builder = mojoBuilder("org.sonatype.tycho", "maven-osgi-test-plugin", "test"); + + MojoInfo mojo = builder.build(); + assertTrue(this.surefireArchiver.isTestMojo(mojo)); + + mojo = builder.copy().configValue("skipTest", "true").build(); + assertFalse(this.surefireArchiver.isTestMojo(mojo)); + } + + @Test + public void shouldDetectTychoSurefirePlugin() { + MojoInfoBuilder builder = mojoBuilder("org.eclipse.tycho", "tycho-surefire-plugin", "test"); + + MojoInfo mojo = builder.build(); + assertTrue(this.surefireArchiver.isTestMojo(mojo)); + + mojo = builder.copy().configValue("skipTest", "true").build(); + assertFalse(this.surefireArchiver.isTestMojo(mojo)); + } + + @Test + public void shouldDetectMavenAndroidPlugin() { + MojoInfoBuilder builder = mojoBuilder("com.jayway.maven.plugins.android.generation2", "maven-android-plugin", "internal-integration-test") + .version("3.0.0-alpha-6"); + + MojoInfo mojo = builder.build(); + assertTrue(this.surefireArchiver.isTestMojo(mojo)); + + mojo = builder.copy().configValue("skipTests", "true").build(); + assertFalse(this.surefireArchiver.isTestMojo(mojo)); + } + + @Test + public void shouldDetectAndroidMavenPlugin() { + MojoInfoBuilder builder = mojoBuilder("com.jayway.maven.plugins.android.generation2", "android-maven-plugin", "internal-integration-test") + .version("3.0.0-alpha-6"); + + MojoInfo mojo = builder.build(); + assertTrue(this.surefireArchiver.isTestMojo(mojo)); + + mojo = builder.copy().configValue("skipTests", "true").build(); + assertFalse(this.surefireArchiver.isTestMojo(mojo)); + } + + @Test + public void shouldDetectGwtMavenPlugin() { + MojoInfoBuilder builder = mojoBuilder("org.codehaus.mojo", "gwt-maven-plugin", "test") + .version("1.2"); + + MojoInfo mojo = builder.build(); + assertTrue(this.surefireArchiver.isTestMojo(mojo)); + + // that version of the plugin is too old + mojo = builder.copy().version("1.1").build(); + assertFalse(this.surefireArchiver.isTestMojo(mojo)); + } + + @Test + public void shouldDetectSoapUiMavenPlugin() { + MojoInfoBuilder builder = mojoBuilder("eviware", "maven-soapui-plugin", "test"); + + MojoInfo mojo = builder.build(); + assertTrue(this.surefireArchiver.isTestMojo(mojo)); + + mojo = builder.copy().configValue("skip", "true").build(); + assertFalse(this.surefireArchiver.isTestMojo(mojo)); + } + + @Test + public void shouldDetectSoapUiProMavenPlugin() { + MojoInfoBuilder builder = mojoBuilder("eviware", "maven-soapui-pro-plugin", "test"); + + MojoInfo mojo = builder.build(); + assertTrue(this.surefireArchiver.isTestMojo(mojo)); + + mojo = builder.copy().configValue("skip", "true").build(); + assertFalse(this.surefireArchiver.isTestMojo(mojo)); + } + + @Test + public void shouldDetectToolkitResolverPlugin() { + MojoInfoBuilder builder = mojoBuilder("org.terracotta.maven.plugins", "toolkit-resolver-plugin", "toolkit-resolve-test"); + + MojoInfo mojo = builder.build(); + assertTrue(this.surefireArchiver.isTestMojo(mojo)); + + mojo = builder.copy().configValue("skipTests", "true").build(); + assertFalse(this.surefireArchiver.isTestMojo(mojo)); + } + + @Test + public void shouldDetectAnyMojoWithATestGoal() { + MojoInfoBuilder builder = mojoBuilder("some.weird.internal","test-mojo", "test"); + + MojoInfo mojo = builder.build(); + assertTrue(this.surefireArchiver.isTestMojo(mojo)); + } +} diff --git a/maven-plugin/src/test/java/hudson/maven/reporters/SurefireArchiverFilterReportsFileTest.java b/maven-plugin/src/test/java/hudson/maven/reporters/SurefireArchiverFilterReportsFileTest.java new file mode 100644 index 0000000000000000000000000000000000000000..0f73c935d4921bb4f104ec0e1b3c58c1f69e348d --- /dev/null +++ b/maven-plugin/src/test/java/hudson/maven/reporters/SurefireArchiverFilterReportsFileTest.java @@ -0,0 +1,101 @@ +package hudson.maven.reporters; + +import static org.junit.Assert.fail; +import static org.mockito.Matchers.any; +import static org.mockito.Matchers.anyString; +import static org.mockito.Mockito.mock; +import static org.mockito.Mockito.spy; +import static org.mockito.Mockito.when; +import hudson.maven.reporters.SurefireArchiver.FilteredReportsFileIterable; + +import java.io.File; +import java.util.Iterator; +import java.util.NoSuchElementException; + +import org.junit.Test; + +public class SurefireArchiverFilterReportsFileTest { + + @Test + public void shouldIncludeAllReportFiles() { + File reportsDir = new File("bla"); + String[] reportFiles = { "a", "b", "c" }; + FilteredReportsFileIterable iterable = new FilteredReportsFileIterable(reportsDir, reportFiles, 0, 1000); + + iterable = spy(iterable); + File file = mock(File.class); + when(file.lastModified()).thenReturn(500L); + + when(iterable.getFile(any(File.class), anyString())).thenReturn(file); + + Iterator iterator = iterable.iterator(); + + iterator.next(); + iterator.next(); + iterator.next(); + + try { + iterator.next(); + fail("Iterator should only have 3 elements"); + } catch (NoSuchElementException e) { + // expected + } + } + + @Test + public void shouldExcludeReportFileTooOld() { + File reportsDir = new File("bla"); + String[] reportFiles = { "a", "b", "c" }; + FilteredReportsFileIterable iterable = new FilteredReportsFileIterable(reportsDir, reportFiles, 5000, 10000); + + iterable = spy(iterable); + File included = mock(File.class); + when(included.lastModified()).thenReturn(6000L); + + File tooOld = mock(File.class); + when(tooOld.lastModified()).thenReturn(500L); + + when(iterable.getFile(any(File.class), anyString())).thenReturn(included, tooOld, included); + + Iterator iterator = iterable.iterator(); + + iterator.next(); + iterator.next(); + + try { + iterator.next(); + fail("Iterator should only have 2 elements"); + } catch (NoSuchElementException e) { + // expected + } + } + + @Test + public void shouldExcludeReportFileTooYoung() { + File reportsDir = new File("bla"); + String[] reportFiles = { "a", "b", "c" }; + FilteredReportsFileIterable iterable = new FilteredReportsFileIterable(reportsDir, reportFiles, 5000, 10000); + + iterable = spy(iterable); + File included = mock(File.class); + when(included.lastModified()).thenReturn(5000L); + + File tooYoung = mock(File.class); + when(tooYoung.lastModified()).thenReturn(20000L); + + when(iterable.getFile(any(File.class), anyString())).thenReturn(included, included, tooYoung); + + Iterator iterator = iterable.iterator(); + + iterator.next(); + iterator.next(); + + try { + iterator.next(); + fail("Iterator should only have 2 elements"); + } catch (NoSuchElementException e) { + // expected + } + } + +} diff --git a/maven-plugin/src/test/java/hudson/maven/reporters/SurefireArchiverUnitTest.java b/maven-plugin/src/test/java/hudson/maven/reporters/SurefireArchiverUnitTest.java index a4d987d08a00a0e37fda3029fce4bfd972bcd9ff..a30cc5322154cf5e69b5517bd4fbd98017c8af12 100644 --- a/maven-plugin/src/test/java/hudson/maven/reporters/SurefireArchiverUnitTest.java +++ b/maven-plugin/src/test/java/hudson/maven/reporters/SurefireArchiverUnitTest.java @@ -1,5 +1,6 @@ package hudson.maven.reporters; +import static org.junit.Assert.assertEquals; import static org.mockito.Mockito.doReturn; import static org.mockito.Mockito.mock; import static org.mockito.Mockito.spy; @@ -13,6 +14,7 @@ import hudson.maven.MavenBuildProxy; import hudson.maven.MavenProjectActionBuilder; import hudson.maven.MavenReporter; import hudson.maven.MojoInfo; +import hudson.maven.MojoInfoBuilder; import hudson.model.BuildListener; import hudson.model.Cause; import hudson.model.Result; @@ -28,10 +30,6 @@ import java.util.Calendar; import java.util.List; import org.apache.commons.io.output.NullOutputStream; -import org.apache.maven.plugin.MojoExecution; -import org.apache.maven.plugin.descriptor.MojoDescriptor; -import org.apache.maven.plugin.descriptor.PluginDescriptor; -import org.apache.tools.ant.types.FileSet; import org.codehaus.plexus.component.configurator.ComponentConfigurationException; import org.junit.Assert; import org.junit.Before; @@ -53,8 +51,6 @@ public class SurefireArchiverUnitTest { @Before @SuppressWarnings("unchecked") public void before() throws ComponentConfigurationException, URISyntaxException { - //suppress(constructor(MavenBuild.class, new Class[0])); - this.archiver = new SurefireArchiver(); this.build = mock(MavenBuild.class); when(build.getAction(Matchers.any(Class.class))).thenCallRealMethod(); @@ -69,17 +65,8 @@ public class SurefireArchiverUnitTest { } private MojoInfo createMojoInfo() throws ComponentConfigurationException { - PluginDescriptor pluginDescriptor = new PluginDescriptor(); - pluginDescriptor.setGroupId("org.apache.maven.plugins"); - pluginDescriptor.setArtifactId("maven-surefire-plugin"); - pluginDescriptor.setVersion("2.9"); - - MojoDescriptor mojoDescriptor = new MojoDescriptor(); - mojoDescriptor.setPluginDescriptor(pluginDescriptor); - mojoDescriptor.setGoal("test"); - - MojoExecution mojoExecution = new MojoExecution(mojoDescriptor); - MojoInfo info = new MojoInfo(mojoExecution, null, null, null); + MojoInfo info = MojoInfoBuilder.mojoBuilder("org.apache.maven.plugins", "maven-surefire-plugin", "test") + .version("2.9").build(); MojoInfo spy = spy(info); @@ -103,6 +90,7 @@ public class SurefireArchiverUnitTest { public void testArchiveResults() throws InterruptedException, IOException, URISyntaxException, ComponentConfigurationException { URL resource = SurefireArchiverUnitTest.class.getResource("/surefire-archiver-test2"); File reportsDir = new File(resource.toURI().getPath()); + doReturn(reportsDir).when(this.mojoInfo).getConfigurationValue("reportsDirectory", File.class); touchReportFiles(reportsDir); @@ -130,19 +118,22 @@ public class SurefireArchiverUnitTest { } @Test - public void testAlreadyCheckedFilesAreNotParsedAgain() throws InterruptedException, IOException, URISyntaxException, ComponentConfigurationException { + public void testResultsAreNotCountedTwice() throws InterruptedException, IOException, URISyntaxException, ComponentConfigurationException { URL resource = SurefireArchiverUnitTest.class.getResource("/surefire-archiver-test2"); File reportsDir = new File(resource.toURI().getPath()); doReturn(reportsDir).when(this.mojoInfo).getConfigurationValue("reportsDirectory", File.class); touchReportFiles(reportsDir); - FileSet fileSet = this.archiver.getFileSet(reportsDir); - Assert.assertEquals(2, fileSet.getDirectoryScanner().getIncludedFilesCount()); + this.archiver.postExecute(buildProxy, null, this.mojoInfo, new NullBuildListener(), null); + SurefireReport action = this.build.getAction(SurefireReport.class); + TestResult result = action.getResult(); + assertEquals(2658, result.getTotalCount()); + // result count shouldn't increase if mojo is called again this.archiver.postExecute(buildProxy, null, this.mojoInfo, new NullBuildListener(), null); - - fileSet = this.archiver.getFileSet(reportsDir); - Assert.assertEquals(0, fileSet.getDirectoryScanner().getIncludedFilesCount()); + action = this.build.getAction(SurefireReport.class); + result = action.getResult(); + assertEquals(2658, result.getTotalCount()); } @Test @@ -205,7 +196,7 @@ public class SurefireArchiverUnitTest { private void touchReportFiles(File reportsDir) { File[] files = reportsDir.listFiles(); for(File f : files) { - f.setLastModified(System.currentTimeMillis()); + f.setLastModified(this.mojoInfo.getStartTime()); } }