package hudson.plugins.japex; import com.sun.japex.report.TestSuiteReport; import hudson.model.Action; import hudson.model.Build; import hudson.model.Project; import org.kohsuke.stapler.StaplerProxy; import org.kohsuke.stapler.StaplerRequest; import org.kohsuke.stapler.StaplerResponse; import org.xml.sax.SAXException; import java.io.File; import java.io.IOException; import java.io.FileFilter; import java.lang.ref.WeakReference; import java.util.ArrayList; import java.util.HashMap; import java.util.List; import java.util.Map; import java.util.Collection; import java.util.logging.Logger; import java.util.logging.Level; import java.util.Map.Entry; /** * Project action to display trend reports. * * @author Kohsuke Kawaguchi */ public class JapexReportAction implements Action, StaplerProxy { private final Project<?,?> project; public JapexReportAction(Project project) { this.project = project; } public Project getProject() { return project; } public String getDisplayName() { return "Japex Trend Report"; } public String getIconFileName() { return "graph.gif"; } public String getUrlName() { return "japex"; } /** * Cached {@link TrendReport}s, keyed by their configuration name. */ private WeakReference<Parsed> cache; private final class Parsed { final Map<String,TrendReport> reports = new HashMap<String,TrendReport>(); final int buildNumber; final TrendReport singleton; public Parsed(Build build, Map<String,List<TestSuiteReport>> reports) { this.buildNumber = build.getNumber(); for (Entry<String,List<TestSuiteReport>> e : reports.entrySet()) { this.reports.put(e.getKey(), new TrendReport(project, e.getKey(), new HudsonChartGenerator(e.getValue(),build))); } if(reports.size()==1) singleton = this.reports.values().iterator().next(); else singleton = null; } } public TrendReport getReport(String configName) throws IOException { return parseReports().reports.get(configName); } public TrendReport getDynamic(String token, StaplerRequest req, StaplerResponse rsp ) throws IOException { return getReport(token); } public boolean hasReports() throws IOException { return !parseReports().reports.isEmpty(); } public Collection<TrendReport> getReports() throws IOException { return parseReports().reports.values(); } /** * If there's only one {@link TrendReport}, simply display that report * on this view. */ public Object getTarget() { try { Parsed parsed = parseReports(); if(parsed.singleton!=null) { // forward to that single test report return parsed.singleton; } else { return this; } } catch (IOException e) { LOGGER.log(Level.WARNING,"Failed to parse Japex reports",e); // this should cause index view to be displayed on this object, // which should report the parse failure return this; } } /** * Creates the {@link HudsonChartGenerator} (or reuse the last one.) */ /*package*/ synchronized Parsed parseReports() throws IOException { Build lb = project.getLastBuild(); if(cache!=null) { Parsed parsed = cache.get(); if(parsed!=null && lb!=null && parsed.buildNumber==lb.getNumber()) return parsed; // reuse the cached instance } // parse reports Map<String,List<TestSuiteReport>> reports = new HashMap<String,List<TestSuiteReport>>(); for (Build build : project.getBuilds()) { File dir = JapexPublisher.getJapexReport(build); File[] files = dir.listFiles(REPORT_FILTER); if(files!=null) { for (File f : files) { try { TestSuiteReport rpt = new TestSuiteReport(f); String configName = rpt.getParameters().get("configFile").replace('/','.'); List<TestSuiteReport> reportList = reports.get(configName); if(reportList==null) { reportList = new ArrayList<TestSuiteReport>(); reports.put(configName,reportList); } reportList.add(rpt); } catch (SAXException e) { IOException x = new IOException("Failed to parse " + f); x.initCause(e); throw x; } catch (RuntimeException e) { // Japex sometimes intentionally send RuntimeException IOException x = new IOException("Failed to parse " + f); x.initCause(e); throw x; } } } } Parsed parsed = new Parsed(lb,reports); cache = new WeakReference<Parsed>(parsed); return parsed; } private static final FileFilter REPORT_FILTER = new FileFilter() { public boolean accept(File f) { return f.getName().endsWith(".xml"); } }; private static final Logger LOGGER = Logger.getLogger(JapexReportAction.class.getName()); }