io.quarkus.jacoco.runtime.ReportCreator Maven / Gradle / Ivy
Go to download
Show more of this group Show more artifacts with this name
Show all versions of quarkus-jacoco Show documentation
Show all versions of quarkus-jacoco Show documentation
Jacoco test coverage support
package io.quarkus.jacoco.runtime;
import java.io.File;
import java.io.FileOutputStream;
import java.io.IOException;
import java.io.PrintStream;
import java.nio.file.Files;
import java.nio.file.Path;
import java.nio.file.Paths;
import java.util.ArrayList;
import java.util.List;
import java.util.Locale;
import org.jacoco.core.analysis.Analyzer;
import org.jacoco.core.analysis.CoverageBuilder;
import org.jacoco.core.analysis.IBundleCoverage;
import org.jacoco.core.tools.ExecFileLoader;
import org.jacoco.report.DirectorySourceFileLocator;
import org.jacoco.report.FileMultiReportOutput;
import org.jacoco.report.IReportVisitor;
import org.jacoco.report.MultiReportVisitor;
import org.jacoco.report.MultiSourceFileLocator;
import org.jacoco.report.csv.CSVFormatter;
import org.jacoco.report.html.HTMLFormatter;
import org.jacoco.report.xml.XMLFormatter;
import org.jboss.logging.Logger;
public class ReportCreator implements Runnable {
private static final Logger log = Logger.getLogger(ReportCreator.class);
private final ReportInfo reportInfo;
private final JacocoConfig config;
public ReportCreator(ReportInfo reportInfo, JacocoConfig config) {
this.reportInfo = reportInfo;
this.config = config;
}
@Override
public void run() {
// Ugly workaround:
// Multiple ReportCreator shutdown hooks might run concurrently, possibly corrupting the report file(s) - e.g. when using @TestProfile.
// By locking on a class from the parent CL, all hooks are "serialized", one after another.
// In the long run there should only be as many hooks as there are different Jacoco configs...usually there will be only one config anyway!
synchronized (ExecFileLoader.class) {
doRun();
}
}
private void doRun() {
File targetdir = new File(reportInfo.reportDir);
targetdir.mkdirs();
try {
//the jacoco data is also generated by a shutdown hook
//we need to wait for the file. We wait at most 10s
long abortTime = System.currentTimeMillis() + 10000;
Path datafile = Paths.get(reportInfo.dataFile);
while (System.currentTimeMillis() < abortTime) {
if (Files.exists(datafile) && Files.size(datafile) > 0) {
break;
}
Thread.sleep(100);
}
//now it is created we wait for Jacoco to stop
//this is awesomely hacky
for (;;) {
boolean running = false;
for (Thread entry : Thread.getAllStackTraces().keySet()) {
if (entry.getClass().getName().startsWith("org.jacoco")) {
running = true;
break;
}
}
if (!running) {
break;
} else {
Thread.sleep(100);
}
}
ExecFileLoader loader = new ExecFileLoader();
for (String i : reportInfo.savedData) {
File file = new File(i);
if (file.exists()) {
loader.load(file);
}
}
final CoverageBuilder builder = new CoverageBuilder();
final Analyzer analyzer = new Analyzer(
loader.getExecutionDataStore(), builder);
for (String i : reportInfo.classFiles) {
File file = new File(i);
if (file.exists()) {
analyzer.analyzeAll(file);
}
}
List formatters = new ArrayList<>();
addXmlFormatter(new File(targetdir, "jacoco.xml"), config.outputEncoding, formatters);
addCsvFormatter(new File(targetdir, "jacoco.csv"), config.outputEncoding, formatters);
addHtmlFormatter(targetdir, config.outputEncoding, config.footer.orElse(""), Locale.getDefault(),
formatters);
//now for the hacky bit
final IReportVisitor visitor = new MultiReportVisitor(formatters);
visitor.visitInfo(loader.getSessionInfoStore().getInfos(),
loader.getExecutionDataStore().getContents());
MultiSourceFileLocator sourceFileLocator = new MultiSourceFileLocator(4);
for (String i : reportInfo.sourceDirectories) {
sourceFileLocator.add(new DirectorySourceFileLocator(new File(i), config.sourceEncoding, 4));
}
final IBundleCoverage bundle = builder.getBundle(config.title.orElse(reportInfo.artifactId));
visitor.visitBundle(bundle, sourceFileLocator);
visitor.visitEnd();
System.out.println("Generated Jacoco reports in " + targetdir);
System.out.flush();
} catch (Exception e) {
System.err.println("Failed to generate Jacoco reports");
e.printStackTrace();
System.err.flush();
File error = new File(targetdir, "error.txt");
try (FileOutputStream out = new FileOutputStream(error)) {
PrintStream ps = new PrintStream(out);
ps.println("Failed to generate Jacoco reports");
e.printStackTrace(ps);
} catch (IOException iugnore) {
//ignore
}
}
}
public void addXmlFormatter(final File targetfile, final String encoding, List formatters)
throws IOException {
final XMLFormatter xml = new XMLFormatter();
xml.setOutputEncoding(encoding);
formatters.add(xml.createVisitor(new FileOutputStream(targetfile)));
}
public void addCsvFormatter(final File targetfile, final String encoding, List formatters)
throws IOException {
final CSVFormatter csv = new CSVFormatter();
csv.setOutputEncoding(encoding);
formatters.add(csv.createVisitor(new FileOutputStream(targetfile)));
}
public void addHtmlFormatter(final File targetdir, final String encoding,
final String footer, final Locale locale, List formatters) throws IOException {
final HTMLFormatter htmlFormatter = new HTMLFormatter();
htmlFormatter.setOutputEncoding(encoding);
htmlFormatter.setLocale(locale);
if (footer != null) {
htmlFormatter.setFooterText(footer);
}
formatters.add(htmlFormatter
.createVisitor(new FileMultiReportOutput(targetdir)));
}
}