File D:\maven-qcr-plugin-testsunitaires\qcr4java\jenkins-master\target\site\qc\maven-plugin\src\main\java\hudson\maven\reporters\SurefireArchiver.java.html

1 /*
2 * The MIT License
3 *
4 * Copyright (c) 2004-2009, Sun Microsystems, Inc., Kohsuke Kawaguchi, Jason Chaffee, Maciek Starzyk
5 *
6 * Permission is hereby granted, free of charge, to any person obtaining a copy
7 * of this software and associated documentation files (the "Software"), to deal
8 * in the Software without restriction, including without limitation the rights
9 * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
10 * copies of the Software, and to permit persons to whom the Software is
11 * furnished to do so, subject to the following conditions:
12 *
13 * The above copyright notice and this permission notice shall be included in
14 * all copies or substantial portions of the Software.
15 *
16 * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
17 * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
18 * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
19 * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
20 * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
21 * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
22 * THE SOFTWARE.
23 */
24 package hudson.maven.reporters;
25
26 import hudson.Extension;
27 import hudson.Launcher;
28 import hudson.maven.Maven3Builder;
29 import hudson.maven.MavenBuild;
30 import hudson.maven.MavenBuildInformation;
31 import hudson.maven.MavenBuildProxy;
32 import hudson.maven.MavenBuildProxy.BuildCallable;
33 import hudson.maven.MavenBuilder;
34 import hudson.maven.MavenModule;
35 import hudson.maven.MavenProjectActionBuilder;
36 import hudson.maven.MavenReporter;
37 import hudson.maven.MavenReporterDescriptor;
38 import hudson.maven.MojoInfo;
39 import hudson.model.Action;
40 import hudson.model.BuildListener;
41 import hudson.model.Result;
42 import hudson.tasks.junit.TestResult;
43 import hudson.tasks.test.TestResultProjectAction;
44
45 import java.io.File;
46 import java.io.IOException;
47 import java.util.Collection;
48 import java.util.Collections;
49 import java.util.Iterator;
50 import java.util.List;
51 import java.util.ListIterator;
52 import java.util.concurrent.ConcurrentHashMap;
53 import java.util.concurrent.ConcurrentMap;
54 import java.util.concurrent.atomic.AtomicBoolean;
55
56 import org.apache.maven.plugin.MojoFailureException;
57 import org.apache.maven.project.MavenProject;
58 import org.codehaus.plexus.component.configurator.ComponentConfigurationException;
59 import org.codehaus.plexus.configuration.xml.XmlPlexusConfiguration;
60 import org.codehaus.plexus.util.xml.Xpp3Dom;
61
62 import com.google.common.base.Function;
63 import com.google.common.base.Predicate;
64 import com.google.common.collect.Iterables;
65 import com.google.common.collect.Iterators;
66
67 /**
68 * Records the surefire test result.
69 * @author Kohsuke Kawaguchi
70 * @author Christoph Kutzinski
71 */
72 public class SurefireArchiver extends TestFailureDetector {
73 private transient TestResult result;
74 private final AtomicBoolean hasTestFailures = new AtomicBoolean();
75
76 /**
77 * Store result files already parsed, so we don't parse them again,
78 * if a later running mojo specifies the same reports directory.
79 */
80 private transient ConcurrentMap<File, File> parsedFiles = new ConcurrentHashMap<File,File>();
81
82 @Override
83 public boolean hasTestFailures() {
84 return hasTestFailures.get();
85 }
86
87 public boolean preExecute(MavenBuildProxy build, MavenProject pom, MojoInfo mojo, BuildListener listener) throws InterruptedException, IOException {
88 if (isTestMojo(mojo)) {
89 // tell test mojo to keep going even if there was a failure,
90 // so that we can record this as yellow.
91 // note that because of the way Maven works, just updating system property at this point is too late
92
93 // Many test plugins have - as surefire - a configuration key 'testFailureIgnore' which defaults to
94 // ${maven.test.failure.ignore}, so just try that one and change value to true,
95 // if it's still at that default:
96 XmlPlexusConfiguration c = (XmlPlexusConfiguration) mojo.configuration.getChild("testFailureIgnore",false);
97 if(c!=null && c.getValue() != null && c.getValue().equals("${maven.test.failure.ignore}") && System.getProperty("maven.test.failure.ignore")==null) {
98 if (build.getMavenBuildInformation().isMaven3OrLater()) {
99 String fieldName = "testFailureIgnore";
100 if (mojo.mojoExecution.getConfiguration().getChild( fieldName ) != null) {
101 mojo.mojoExecution.getConfiguration().getChild( fieldName ).setValue( Boolean.TRUE.toString() );
102 } else {
103 Xpp3Dom child = new Xpp3Dom( fieldName );
104 child.setValue( Boolean.TRUE.toString() );
105 mojo.mojoExecution.getConfiguration().addChild( child );
106 }
107
108 } else {
109 c.setValue(Boolean.TRUE.toString());
110 }
111 }
112 }
113 return true;
114 }
115
116 public boolean postExecute(MavenBuildProxy build, MavenProject pom, MojoInfo mojo, final BuildListener listener, Throwable error) throws InterruptedException, IOException {
117 TestMojo testMojo = getTestMojo(mojo);
118 if (testMojo == null) return true;
119
120 listener.getLogger().println(Messages.SurefireArchiver_Recording());
121
122 Iterable<File> fileSet;
123
124 try {
125 fileSet = testMojo.getReportFiles(pom, mojo);
126 } catch (ComponentConfigurationException e) {
127 e.printStackTrace(listener.fatalError(Messages.SurefireArchiver_NoReportsDir()));
128 build.setResult(Result.FAILURE);
129 return true;
130 }
131
132 if(fileSet != null) {
133 synchronized (build) {
134
135 if(result==null) result = new TestResult();
136
137 // filter all the already parsed files:
138 fileSet = Iterables.filter(fileSet, new Predicate<File>() {
139 @Override
140 public boolean apply(File input) {
141 return !parsedFiles.containsKey(input);
142 }
143 });
144
145 if (!fileSet.iterator().hasNext())
146 return true;
147
148 result.parse(System.currentTimeMillis() - build.getMilliSecsSinceBuildStart(), fileSet);
149 // TODO kutzi: the following is a 'more correct' way to get the reports associated to a mojo,
150 // but needs more testing
151 // Iterable<File> reportFilesFiltered = getFilesBetween(reportsDir, reportFiles, mojo.getStartTime(), System.currentTimeMillis());
152 // result.parse(reportFilesFiltered);
153
154
155 rememberCheckedFiles(fileSet);
156
157 // final reference in order to serialize it:
158 final TestResult r = result;
159
160 int failCount = build.execute(new BuildCallable<Integer, IOException>() {
161 private static final long serialVersionUID = -1023888330720922136L;
162
163 public Integer call(MavenBuild build) throws IOException, InterruptedException {
164 SurefireReport sr = build.getAction(SurefireReport.class);
165 if(sr==null)
166 build.getActions().add(new SurefireReport(build, r, listener));
167 else
168 sr.setResult(r,listener);
169 if(r.getFailCount()>0)
170 build.setResult(Result.UNSTABLE);
171 build.registerAsProjectAction(new FactoryImpl());
172 return r.getFailCount();
173 }
174 });
175
176 // if surefire plugin is going to kill maven because of a test failure,
177 // intercept that (or otherwise build will be marked as failure)
178 if(failCount>0) {
179 markBuildAsSuccess(error,build.getMavenBuildInformation());
180 hasTestFailures.set(true);
181 }
182 }
183 }
184
185 return true;
186 }
187
188 @Override
189 public boolean end(MavenBuild build, Launcher launcher, BuildListener listener) throws InterruptedException, IOException {
190 //Discard unneeded test result objects so they can't waste memory
191 for(MavenReporter reporter: build.getProject().getReporters()) {
192 if(reporter instanceof SurefireArchiver) {
193 SurefireArchiver surefireReporter = (SurefireArchiver) reporter;
194 if(surefireReporter.result != null) {
195 surefireReporter.result = null;
196 }
197 }
198 }
199 return true;
200 }
201
202 @edu.umd.cs.findbugs.annotations.SuppressWarnings(value="ST_WRITE_TO_STATIC_FROM_INSTANCE_METHOD", justification="It's okay to write to static fields here, as each Maven build is started in its own VM")
203 private void markBuildAsSuccess(Throwable mojoError, MavenBuildInformation buildInfo) {
204 if(mojoError == null // in the success case we don't get any exception in Maven 3.0.2+; Maven < 3.0.2 returns no exception anyway
205 || mojoError instanceof MojoFailureException) {
206 MavenBuilder.markAsSuccess = true;
207 Maven3Builder.markAsSuccess = true;
208 }
209 }
210
211 /**
212 * Add checked files to the exclude list of the fileSet
213 */
214 private void rememberCheckedFiles(Iterable<File> fileSet) {
215 for (File f : fileSet) {
216 this.parsedFiles.put(f, f);
217 }
218 }
219
220 /**
221 * Up to 1.372, there was a bug that causes Hudson to persist {@link SurefireArchiver} with the entire test result
222 * in it. If we are loading those, fix it up in memory to reduce the memory footprint.
223 *
224 * It'd be nice we can save the record to remove problematic portion, but that might have
225 * additional side effect.
226 */
227 public static void fixUp(List<MavenProjectActionBuilder> builders) {
228 if (builders==null) return;
229 for (ListIterator<MavenProjectActionBuilder> itr = builders.listIterator(); itr.hasNext();) {
230 MavenProjectActionBuilder b = itr.next();
231 if (b instanceof SurefireArchiver)
232 itr.set(new FactoryImpl());
233 }
234 }
235
236 // private static Iterable<File> getFilesBetween(final File reportsDir,
237 // final String[] reportFiles, final long from, final long to) {
238 // return new FilteredReportsFileIterable(reportsDir, reportFiles, from, to);
239 // }
240
241 /**
242 * Provides an {@link Iterable} view on the reports files while filtering out all files
243 * which don't have a lastModified time in between from and to.
244 */
245 static class FilteredReportsFileIterable implements Iterable<File> {
246 private final File reportsDir;
247 private final String[] reportFiles;
248 private final long from;
249 private final long to;
250
251 FilteredReportsFileIterable(File reportsDir,
252 String[] reportFiles, long from, long to) {
253 this.reportsDir = reportsDir;
254 this.reportFiles = reportFiles;
255
256 // FAT filesystems have a max resolution of 2 seconds so we need to subtract/add 2 seconds to
257 // the range borders.
258 // All other fs should have a equal or better precision
259 this.from = from - 2000;
260 this.to = to + 2000;
261 }
262
263 @Override
264 public Iterator<File> iterator() {
265
266 Predicate<File> fileWithinFromAndTo = new Predicate<File>() {
267 @Override
268 public boolean apply(File file) {
269 long lastModified = file.lastModified();
270 if (lastModified>=from && lastModified<=to) {
271 return true;
272 }
273 return false;
274 }
275 };
276
277 return Iterators.filter(
278 Iterators.transform(
279 Iterators.forArray(reportFiles),
280 new Function<String, File>() {
281 @Override
282 public File apply(String file) {
283 return getFile(reportsDir,file);
284 }
285 }),
286 fileWithinFromAndTo);
287 }
288
289 // here for mocking purposes:
290 File getFile(File parent, String child) {
291 return new File(parent,child);
292 }
293 }
294
295 /**
296 * Part of the serialization data attached to {@link MavenBuild}.
297 */
298 static final class FactoryImpl implements MavenProjectActionBuilder {
299 public Collection<? extends Action> getProjectActions(MavenModule module) {
300 return Collections.singleton(new TestResultProjectAction(module));
301 }
302 }
303
304 boolean isTestMojo(MojoInfo mojo) {
305 return getTestMojo(mojo) != null;
306 }
307
308 private TestMojo getTestMojo(MojoInfo mojo) {
309 TestMojo testMojo = TestMojo.lookup(mojo);
310
311 if (testMojo == null)
312 return null;
313
314 try {
315 // most test plugins have at least on of the test-skip properties:
316 String[] skipProperties = {"skip", "skipExec", "skipTests", "skipTest"};
317 for (String skipProperty : skipProperties) {
318 Boolean skip = mojo.getConfigurationValue(skipProperty, Boolean.class);
319 if (((skip != null) && (skip))) {
320 return null;
321 }
322 }
323 } catch (ComponentConfigurationException e) {
324 return null;
325 }
326
327 return testMojo;
328 }
329
330 // I'm not sure if SurefireArchiver is actually ever (de-)serialized,
331 // but just to be sure, set fileSets here
332 protected Object readResolve() {
333 parsedFiles = new ConcurrentHashMap<File,File>();
334 return this;
335 }
336
337 @Extension
338 public static final class DescriptorImpl extends MavenReporterDescriptor {
339 public String getDisplayName() {
340 return Messages.SurefireArchiver_DisplayName();
341 }
342
343 public SurefireArchiver newAutoInstance(MavenModule module) {
344 return new SurefireArchiver();
345 }
346 }
347
348 private static final long serialVersionUID = 1L;
349 }
350