package hudson.plugins.PerfPublisher; import java.util.ArrayList; import java.util.Collections; import java.util.Comparator; import java.util.HashMap; import java.util.Iterator; import java.util.List; import java.util.Map; import java.util.Set; import java.util.TreeMap; import java.util.Map.Entry; import org.apache.commons.lang.text.StrBuilder; import hudson.matrix.AxisList; import hudson.matrix.MatrixBuild; import hudson.matrix.MatrixProject; import hudson.model.AbstractBuild; import hudson.model.Action; import hudson.plugins.PerfPublisher.Report.ReportContainer; import hudson.plugins.PerfPublisher.Report.Test; import hudson.plugins.PerfPublisher.matrixBuild.PerfPublisherMatrixBuild; import hudson.plugins.PerfPublisher.matrixBuild.PerfPublisherMatrixSubBuild; public class MatrixTestReportAction extends AbstractPerfPublisherAction implements Action { PerfPublisherMatrixBuild matrixbuild; private int numberOfExecutedTest; private int numberOfTest; private int numberOfPassedTest; private int numberOfNotExecutedTest; private int numberOfTrueFalseTest; private int numberOfFailedTest; private MatrixBuild build; private MatrixProject project; public MatrixTestReportAction(MatrixBuild build) { this.matrixbuild = new PerfPublisherMatrixBuild(build.getNumber()); this.build = build; this.project = build.getProject(); } public MatrixBuild getBuild() { return build; } public MatrixProject getProject() { return project; } public String getDisplayName() { return PerfPublisherPlugin.MATRIX_BUILD_DISPLAY_NAME; } public String getSearchUrl() { return PerfPublisherPlugin.URL; } public String getIconFileName() { return PerfPublisherPlugin.ICON_FILE_NAME; } public String getUrlName() { return PerfPublisherPlugin.URL; } /** * Add a subBuild result * @param report * @param buildVariables */ public void addSubBuildResult(ReportContainer report, Map<String, String> buildVariables) { Map<String, String> buildVars = new TreeMap<String, String>(); buildVars.putAll(buildVariables); this.matrixbuild.addSubBuild(new PerfPublisherMatrixSubBuild(buildVars, report)); computeStats(); } public PerfPublisherMatrixBuild getMatrixBuild() { return this.matrixbuild; } public void computeStats() { numberOfExecutedTest = 0; numberOfFailedTest = 0; numberOfTest = 0; numberOfPassedTest = 0; numberOfTrueFalseTest = 0; List<PerfPublisherMatrixSubBuild> subBuilds = this.matrixbuild.getSubBuilds(); for (int i=0; i<subBuilds.size(); i++) { this.numberOfExecutedTest+=subBuilds.get(i).getReport().getNumberOfExecutedTest(); this.numberOfFailedTest+=subBuilds.get(i).getReport().getNumberOfFailedTest(); this.numberOfTest+=subBuilds.get(i).getReport().getNumberOfTest(); this.numberOfPassedTest+=subBuilds.get(i).getReport().getNumberOfPassedTest(); this.numberOfTrueFalseTest+=subBuilds.get(i).getReport().getNumberOfTrueFalseTest(); } } /** * @return Summary HTML */ public String getSummary() { StringBuilder strbuilder = new StringBuilder(); strbuilder.append("<div class=\"progress-container\">"); int tmp1 = this.getNumberOfFailedTest(); int tmp2 = this.getNumberOfPassedTest(); double tmp3 = this.getPercentOfFailedTest(); double tmp4 = this.getPercentOfPassedTest(); if (tmp3<15) { strbuilder.append("<div id=\"red\" style=\"width:15%;\">"+tmp1+"</div>"); strbuilder.append("<div id=\"blue\" style=\"width:85%;\">"+tmp2+"</div>"); } else { strbuilder.append("<div id=\"red\" style=\"width:"+tmp3+"%;\">"+tmp3+"% ("+tmp1+")</div>"); strbuilder.append("<div id=\"blue\" style=\"width:"+tmp4+"%;\">"+tmp4+"% ("+tmp2+")</div>"); } strbuilder.append("</div>"); return strbuilder.toString(); } private int getNumberOfFailedTest() { return this.numberOfFailedTest; } private int getNumberOfPassedTest() { return this.numberOfPassedTest; } private int getNumberOfTrueFalseTest() { return this.numberOfTrueFalseTest; } private double getPercentOfFailedTest() { double resultat = 0; resultat = ((double) getNumberOfFailedTest() / getNumberOfTrueFalseTest()) * 100; return floor(resultat, 2); } private double getPercentOfPassedTest() { double resultat = 0; resultat = ((double) getNumberOfPassedTest() / getNumberOfTrueFalseTest()) * 100; return floor(resultat, 2); } /** * Round a double with n decimals * * @param a * value to convert * @param n * Number of decimals * @return the rounded number */ public static double floor(double a, int n) { double p = Math.pow(10.0, n); return Math.floor((a * p) + 0.5) / p; } public String getDetailSummary() { StringBuilder strbuilder = new StringBuilder(); strbuilder.append("Number of executed tests : <b>"+this.getNumberOfExecutedTest()+".</b>"); strbuilder.append("<br />"); return strbuilder.toString(); } // public String getRegression() { // // StringBuilder strb = new StringBuilder(); // List<Test> regressions = new ArrayList<Test>(); // if (this.getTrendReport()!=null) { // List<Test> tmpTests = this.getTrendReport().getSuccessStatusChangedTests(); // for (int i=0; i<tmpTests.size(); i++) { // if (!tmpTests.get(i).isSuccessfull()) { // regressions.add(tmpTests.get(i)); // } // } // if (!regressions.isEmpty()) { // strb.append("<div class=\"warning_regression\">"); // strb.append("This build has discovered "+regressions.size()+" regression(s)."); // strb.append("</div>"); // } // } // // return strb.toString(); // } public String getHtmlArrayDisplay() { StringBuilder strb = new StringBuilder(); /** * Generate HTML Header Table */ strb.append("<table class=\"matrix_table\">\n"); strb.append(generateHtmlArrayHeader()); /** * Generate HTML Table Content */ strb.append(generateHtmlArrayContent()); strb.append("</table>"); return strb.toString(); } private String generateHtmlArrayContent() { StringBuilder strb = new StringBuilder(); List<PerfPublisherMatrixSubBuild> subBuilds = this.matrixbuild.getSubBuilds(); Collections.sort(subBuilds); Map<String, List<Integer>> values = new HashMap<String, List<Integer>>(); for (int i=0; i<subBuilds.size(); i++) { if (values.containsKey("Nb tests")) { List<Integer> nbs = values.get("Nb tests"); nbs.add(subBuilds.get(i).getReport().getNumberOfTest()); } else { List<Integer> nbs = new ArrayList<Integer>(); nbs.add(subBuilds.get(i).getReport().getNumberOfTest()); values.put("Nb tests", nbs); } if (values.containsKey("Nb Executed tests")) { List<Integer> nbs = values.get("Nb Executed tests"); nbs.add(subBuilds.get(i).getReport().getNumberOfExecutedTest()); } else { List<Integer> nbs = new ArrayList<Integer>(); nbs.add(subBuilds.get(i).getReport().getNumberOfExecutedTest()); values.put("Nb Executed tests", nbs); } if (values.containsKey("Nb not executed tests")) { List<Integer> nbs = values.get("Nb not executed tests"); nbs.add(subBuilds.get(i).getReport().getNumberOfNotExecutedTest()); } else { List<Integer> nbs = new ArrayList<Integer>(); nbs.add(subBuilds.get(i).getReport().getNumberOfNotExecutedTest()); values.put("Nb not executed tests", nbs); } if (values.containsKey("Succeeded tests")) { List<Integer> nbs = values.get("Succeeded tests"); nbs.add(subBuilds.get(i).getReport().getNumberOfPassedTest()); } else { List<Integer> nbs = new ArrayList<Integer>(); nbs.add(subBuilds.get(i).getReport().getNumberOfPassedTest()); values.put("Succeeded tests", nbs); } if (values.containsKey("Failed tests")) { List<Integer> nbs = values.get("Failed tests"); nbs.add(subBuilds.get(i).getReport().getNumberOfFailedTest()); } else { List<Integer> nbs = new ArrayList<Integer>(); nbs.add(subBuilds.get(i).getReport().getNumberOfFailedTest()); values.put("Failed tests", nbs); } if (values.containsKey("Avg Compile time")) { List<Integer> nbs = values.get("Avg Compile time"); nbs.add((int)subBuilds.get(i).getReport().getAverageOfCompileTime()); } else { List<Integer> nbs = new ArrayList<Integer>(); nbs.add((int)subBuilds.get(i).getReport().getAverageOfCompileTime()); values.put("Avg Compile time", nbs); } if (values.containsKey("Avg Execution time")) { List<Integer> nbs = values.get("Avg Execution time"); nbs.add((int)subBuilds.get(i).getReport().getAverageOfExecutionTime()); } else { List<Integer> nbs = new ArrayList<Integer>(); nbs.add((int)subBuilds.get(i).getReport().getAverageOfExecutionTime()); values.put("Avg Execution time", nbs); } if (values.containsKey("Avg Performance")) { List<Integer> nbs = values.get("Avg Performance"); nbs.add((int)subBuilds.get(i).getReport().getAverageOfPerformance()); } else { List<Integer> nbs = new ArrayList<Integer>(); nbs.add((int)subBuilds.get(i).getReport().getAverageOfPerformance()); values.put("Avg Performance", nbs); } } strb.append(generateHtmlContentRow(values)); return strb.toString(); } private String generateHtmlContentRow(Map<String, List<Integer>> values) { StringBuilder strb = new StringBuilder(); Set<Entry<String, List<Integer>>> entry = values.entrySet(); Iterator<Entry<String, List<Integer>>> iterator = entry.iterator(); int zebra = 2; while (iterator.hasNext()) { Entry<String, List<Integer>> axe = iterator.next(); strb.append("<tr class=\"zebra"+zebra+"\">\n"); strb.append("<td class=\"header\"><small>"+axe.getKey()+"</small></td>\n"); List<Integer> i_min = new ArrayList<Integer>(); int tmp_min = 0; List<Integer> i_max = new ArrayList<Integer>(); int tmp_max = 0; for (int i=0; i<axe.getValue().size(); i++) { /** * Compute min and max * !! I Know this should be improve */ for (int j=0; j<axe.getValue().size(); j++) { if (j==0) { tmp_min = axe.getValue().get(j); tmp_max = axe.getValue().get(j); i_min.add(j); i_max.add(j); } else { if (tmp_min>axe.getValue().get(j)) { tmp_min = axe.getValue().get(j); i_min = new ArrayList<Integer>(); i_min.add(j); } if (tmp_max<axe.getValue().get(j)) { tmp_max = axe.getValue().get(j); i_max = new ArrayList<Integer>(); i_max.add(j); } if (tmp_min == axe.getValue().get(j)) { i_min.add(j); } if (tmp_max == axe.getValue().get(j)) { i_max.add(j); } } } if (i_min.contains(i)) { strb.append("<td class=\"min\">"+axe.getValue().get(i)+"</td>"); } else if (i_max.contains(i)) { strb.append("<td class=\"max\">"+axe.getValue().get(i)+"</td>"); } else { strb.append("<td>"+axe.getValue().get(i)+"</td>"); } } strb.append("</tr>\n"); if (zebra==1) { zebra = 2; } else { zebra = 1; } } return strb.toString(); } private String generateHtmlArrayHeader() { StringBuilder strb = new StringBuilder(); // /** // * First a row which contains as cols as combinations // */ // strb.append("<thead>\n"); // strb.append("<tr>\n"); // // strb.append("<th>Sub-Builds</hd>\n"); // for (int i=0; i<this.matrixbuild.getNbCombinations(); i++) { // strb.append("<th>"+i+"</th>\n"); // } // strb.append("</tr>\n"); // strb.append("</thead>\n"); /** * Rows for each axis */ int factor = 1; int colspan = this.matrixbuild.getNbCombinations(); for (int i_row=0; i_row<this.matrixbuild.getNbAxis(); i_row++) { strb.append("<tr>"); String axis = this.matrixbuild.getAxis().get(i_row); /** * Add the row description */ strb.append("<td class=\"axe\">"+axis+"</td>\n"); /** * Separate the current row with axis values cols */ List<String> values = matrixbuild.getAxisValues(axis); Collections.sort(values); colspan = colspan/values.size(); /** * repeat axis cols on the same row */ for (int i_factor=0; i_factor<factor; i_factor++) { for (int i_value=0; i_value<values.size(); i_value++) { if (colspan > 1) { strb.append("<td COLSPAN="+colspan+" class=\"axe_value\">"+values.get(i_value)+"</td>"); } else { strb.append("<td class=\"axe_value\">"+values.get(i_value)+"</td>\n"); } } } factor *= values.size(); strb.append("</tr>\n"); } return strb.toString(); } public int getNumberOfExecutedTest() { return numberOfExecutedTest; } }