SurefireArchiver.java 12.0 KB
Newer Older
K
kohsuke 已提交
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23
/*
 * The MIT License
 * 
 * Copyright (c) 2004-2009, Sun Microsystems, Inc., Kohsuke Kawaguchi, Jason Chaffee, Maciek Starzyk
 * 
 * Permission is hereby granted, free of charge, to any person obtaining a copy
 * of this software and associated documentation files (the "Software"), to deal
 * in the Software without restriction, including without limitation the rights
 * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
 * copies of the Software, and to permit persons to whom the Software is
 * furnished to do so, subject to the following conditions:
 * 
 * The above copyright notice and this permission notice shall be included in
 * all copies or substantial portions of the Software.
 * 
 * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
 * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
 * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
 * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
 * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
 * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
 * THE SOFTWARE.
 */
24 25
package hudson.maven.reporters;

26
import hudson.Extension;
27
import hudson.Util;
S
Seiji Sogabe 已提交
28
import hudson.maven.Maven3Builder;
29 30 31
import hudson.maven.MavenBuild;
import hudson.maven.MavenBuildProxy;
import hudson.maven.MavenBuildProxy.BuildCallable;
K
kohsuke 已提交
32
import hudson.maven.MavenBuilder;
33
import hudson.maven.MavenModule;
34
import hudson.maven.MavenProjectActionBuilder;
35 36 37
import hudson.maven.MavenReporter;
import hudson.maven.MavenReporterDescriptor;
import hudson.maven.MojoInfo;
38
import hudson.model.Action;
39 40 41
import hudson.model.BuildListener;
import hudson.model.Result;
import hudson.tasks.junit.TestResult;
42
import hudson.tasks.test.TestResultProjectAction;
43 44 45

import java.io.File;
import java.io.IOException;
46 47
import java.util.Collection;
import java.util.Collections;
48
import java.util.HashMap;
49 50
import java.util.List;
import java.util.ListIterator;
51
import java.util.Map;
52

53 54 55 56 57 58 59 60 61 62
import org.apache.commons.lang.StringUtils;
import org.apache.maven.artifact.versioning.ComparableVersion;
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;

63 64 65 66 67
/**
 * Records the surefire test result.
 * @author Kohsuke Kawaguchi
 */
public class SurefireArchiver extends MavenReporter {
68
    private TestResult result;
69 70 71 72 73 74 75
    
    /**
     * Store the filesets here as we want to track ignores between multiple runs of this class<br/>
     * Note: Because this class can be run with different mojo goals with different path settings, 
     * we track multiple {@link FileSet}s for each encountered <tt>reportsDir</tt>
     */
    private transient Map<File, FileSet> fileSets;
76

77
    public boolean preExecute(MavenBuildProxy build, MavenProject pom, MojoInfo mojo, BuildListener listener) throws InterruptedException, IOException {
K
kohsuke 已提交
78
        if (isSurefireTest(mojo)) {
79 80 81 82 83
            if (!mojo.is("org.apache.maven.plugins", "maven-failsafe-plugin", "integration-test")) {
                // 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");
84 85 86 87 88 89 90 91 92 93 94 95 96 97 98
                if(c!=null && c.getValue().equals("${maven.test.failure.ignore}") && System.getProperty("maven.test.failure.ignore")==null) {
                    if (maven3orLater( build.getMavenBuildInformation().getMavenVersion() )) {
                        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 );
                        }
                        
                    } else {
                        c.setValue(Boolean.TRUE.toString());
                    }
                }
99
            }
K
kohsuke 已提交
100
        }
101 102 103
        return true;
    }

104
    public boolean postExecute(MavenBuildProxy build, MavenProject pom, MojoInfo mojo, final BuildListener listener, Throwable error) throws InterruptedException, IOException {
105 106
        if (!isSurefireTest(mojo)) return true;

K
i18n  
kohsuke 已提交
107
        listener.getLogger().println(Messages.SurefireArchiver_Recording());
108

109
        File reportsDir;
110 111
        if (mojo.is("org.apache.maven.plugins", "maven-surefire-plugin", "test") ||
            mojo.is("org.apache.maven.plugins", "maven-failsafe-plugin", "integration-test")) {
112 113 114 115 116 117 118 119 120 121
            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");
122 123 124 125 126
        }

        if(reportsDir.exists()) {
            // surefire:test just skips itself when the current project is not a java project

127 128
        	FileSet fileSet = getFileSet(reportsDir);
            DirectoryScanner ds = fileSet.getDirectoryScanner();
129 130 131 132

            if(ds.getIncludedFiles().length==0)
                // no test in this module
                return true;
133 134
            
            rememberCheckedFiles(reportsDir, ds);
135

136 137
            if(result==null)    result = new TestResult();
            result.parse(System.currentTimeMillis() - build.getMilliSecsSinceBuildStart(), ds);
138

139 140
            int failCount = build.execute(new BuildCallable<Integer, IOException>() {
                public Integer call(MavenBuild build) throws IOException, InterruptedException {
141 142 143 144 145 146
                    SurefireReport sr = build.getAction(SurefireReport.class);
                    if(sr==null)
                        build.getActions().add(new SurefireReport(build, result, listener));
                    else
                        sr.setResult(result,listener);
                    if(result.getFailCount()>0)
147
                        build.setResult(Result.UNSTABLE);
148
                    build.registerAsProjectAction(new FactoryImpl());
149
                    return result.getFailCount();
150 151
                }
            });
152 153 154 155

            // if surefire plugin is going to kill maven because of a test failure,
            // intercept that (or otherwise build will be marked as failure)
            if(failCount>0 && error instanceof MojoFailureException) {
156
                MavenBuilder.markAsSuccess = true;
157
            }
S
Seiji Sogabe 已提交
158 159 160 161
            // TODO currenlty error is empty : will be here with maven 3.0.2+
            if(failCount>0) {
                Maven3Builder.markAsSuccess = true;
            }            
162 163 164 165
        }

        return true;
    }
166 167 168 169 170 171 172 173 174 175 176 177 178 179 180 181 182 183 184 185 186 187 188 189 190 191 192 193 194 195 196
    
    /**
     * Returns the appropriate FileSet for the selected baseDir
     * @param baseDir
     * @return
     */
    private synchronized FileSet getFileSet(File baseDir) {
    	if (fileSets == null) {
    		 fileSets = Collections.synchronizedMap(new HashMap<File, FileSet>());
    	}
    	
    	FileSet fs = fileSets.get(baseDir);
    	
    	if (fs == null) {
    		fs = Util.createFileSet(baseDir, "*.xml","testng-results.xml,testng-failed.xml");
    		fileSets.put(baseDir, fs);
    	}
    	
    	return fs;
    }
    
    /**
     * Add checked files to the exclude list of the fileSet
     */
    private void rememberCheckedFiles(File baseDir, DirectoryScanner ds) {
    	FileSet fileSet = getFileSet(baseDir);
    	
    	for (String file : ds.getIncludedFiles()) {
    		fileSet.setExcludes(file);
    	}
    }
197

198 199 200 201 202 203 204 205 206 207 208 209 210 211 212 213
    /**
     * Up to 1.372, there was a bug that causes Hudson to persist {@link SurefireArchiver} with the entire test result
     * in it. If we are loading those, fix it up in memory to reduce the memory footprint.
     *
     * It'd be nice we can save the record to remove problematic portion, but that might have
     * additional side effect.
     */
    public static void fixUp(List<MavenProjectActionBuilder> builders) {
        if (builders==null) return;
        for (ListIterator<MavenProjectActionBuilder> itr = builders.listIterator(); itr.hasNext();) {
            MavenProjectActionBuilder b =  itr.next();
            if (b instanceof SurefireArchiver)
                itr.set(new FactoryImpl());
        }
    }

214 215 216 217 218 219 220
    /**
     * Part of the serialization data attached to {@link MavenBuild}.
     */
    static final class FactoryImpl implements MavenProjectActionBuilder {
        public Collection<? extends Action> getProjectActions(MavenModule module) {
            return Collections.singleton(new TestResultProjectAction(module));
        }
221 222
    }

223
    private boolean isSurefireTest(MojoInfo mojo) {
224
        if ((!mojo.is("com.sun.maven", "maven-junit-plugin", "test"))
225
            && (!mojo.is("org.sonatype.flexmojos", "flexmojos-maven-plugin", "test-run"))
226 227
            && (!mojo.is("org.apache.maven.plugins", "maven-surefire-plugin", "test"))
            && (!mojo.is("org.apache.maven.plugins", "maven-failsafe-plugin", "integration-test")))
K
kohsuke 已提交
228 229 230
            return false;

        try {
231 232 233
            if (mojo.is("org.apache.maven.plugins", "maven-surefire-plugin", "test")) {
                Boolean skip = mojo.getConfigurationValue("skip", Boolean.class);
                if (((skip != null) && (skip))) {
K
TAB->WS  
kohsuke 已提交
234 235
                    return false;
                }
236 237 238 239 240 241 242 243 244 245 246 247 248 249 250 251
                
                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;
                    }
                }
K
TAB->WS  
kohsuke 已提交
252
            }
253
            else if (mojo.is("com.sun.maven", "maven-junit-plugin", "test")) {
K
TAB->WS  
kohsuke 已提交
254
                Boolean skipTests = mojo.getConfigurationValue("skipTests", Boolean.class);
255
                
K
TAB->WS  
kohsuke 已提交
256 257 258 259
                if (((skipTests != null) && (skipTests))) {
                    return false;
                }
            }
260 261 262 263 264 265 266
            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;
		}
	    }
J
jasonchaffee 已提交
267

K
kohsuke 已提交
268 269 270
        } catch (ComponentConfigurationException e) {
            return false;
        }
K
TAB->WS  
kohsuke 已提交
271

J
jasonchaffee 已提交
272
        return true;
273
    }
274 275 276 277 278 279 280 281
    
    public boolean maven3orLater(String mavenVersion) {
        // null or empty so false !
        if (StringUtils.isBlank( mavenVersion )) {
            return false;
        }
        return new ComparableVersion (mavenVersion).compareTo( new ComparableVersion ("3.0") ) >= 0;
    }       
282

283
    @Extension
284 285
    public static final class DescriptorImpl extends MavenReporterDescriptor {
        public String getDisplayName() {
K
i18n  
kohsuke 已提交
286
            return Messages.SurefireArchiver_DisplayName();
287 288 289 290 291 292
        }

        public SurefireArchiver newAutoInstance(MavenModule module) {
            return new SurefireArchiver();
        }
    }
293 294

    private static final long serialVersionUID = 1L;
295
}