diff --git a/README.md b/README.md index cf6b973..1052199 100644 --- a/README.md +++ b/README.md @@ -1,6 +1,6 @@ # Generating JUnit Report based on custom Key Performance Indicators (KPIs) applied to the JMeter Report CSV file -This tool read KPI declarations in a file and apply the KPI assertion on a JMeter Report CSV file and generates a result file in JUnit XML format. +This tool read KPI declarations in a file and apply the KPI assertion on a JMeter Report CSV file and generates a result file in JUnit XML format and others formats Html, Json and Csv. JMeter Report CSV file is created with Listener : - Summary Report, documentation at [Summary Report](https://jmeter.apache.org/usermanual/component_reference.html#Summary_Report) @@ -50,19 +50,27 @@ Save in UTF-8 comma separator **no BOM** or csv with comma separator if you have ## Parameters The tool have parameters :
-usage: io.github.vdaburon.jmeter.utils.reportkpi.JUnitReportFromJMReportCsv -csvJMReport <csvJMReport> [-csvLabelColumnName <csvLabelColumnName>]
-       [-exitReturnOnFail <exitReturnOnFail>] [-help] [-junitFile <junitFile>] -kpiFile <kpiFile>
+usage: io.github.vdaburon.jmeter.utils.reportkpi.JUnitReportFromJMReportCsv -csvJMReport <csvJMReport> [-csvLabelColumnName
+       <csvLabelColumnName>] [-csvOutFile <csvOutFile>] [-divHtmlOutFile <divHtmlOutFile>] [-exitReturnOnFail <exitReturnOnFail>] [-help]
+       [-htmlOutFile <htmlOutFile>] [-jsonOutFile <jsonOutFile>] [-junitFile <junitFile>] -kpiFile <kpiFile>
 io.github.vdaburon.jmeter.utils.reportkpi.JUnitReportFromJMReportCsv
- -csvJMReport <csvJMReport>                 JMeter report csv file (E.g : summary.csv or aggregate.csv or synthesis.csv)
- -csvLabelColumnName <csvLabelColumnName>   Label Column Name in CSV JMeter Report (Default : Label)
- -exitReturnOnFail <exitReturnOnFail>       if true then when kpi fail then create JUnit XML file and program return exit 1 (KO); if false
+ -csvJMReport <csvJMReport>                 JMeter report csv file (E.g: summary.csv or aggregate.csv or synthesis.csv)
+ -csvLabelColumnName <csvLabelColumnName>   Label Column Name in CSV JMeter Report (Default: Label)
+ -csvOutFile <csvOutFile>                   Csv out file result optional (E.g: result.csv)
+ -divHtmlOutFile <divHtmlOutFile>           Div Partial Html Page out file result optional (E.g: div_result.html), to include in an another
+                                            HTML Page
+ -exitReturnOnFail <exitReturnOnFail>       If true then when kpi fail then create JUnit XML file and program return exit 1 (KO); If false
                                             (Default) then create JUnit XML File and exit 0 (OK)
  -help                                      Help and show parameters
- -junitFile <junitFile>                     junit file name out (Default : jmeter-junit-plugin-jmreport.xml)
- -kpiFile <kpiFile>                         KPI file contains rule to check (E.g : kpi.csv)
-E.g : java -jar junit-reporter-kpi-from-jmeter-report-csv-<version>-jar-with-dependencies.jar -csvJMReport summary.csv  -kpiFile kpi.csv -exitReturnOnFail true
-or more parameters : java -jar junit-reporter-kpi-from-jmeter-report-csv-<version>-jar-with-dependencies.jar -csvJMReport AggregateReport.csv  -csvLabelColumnName Label 
--kpiFile kpi_check.csv -junitFile junit.xml -exitReturnOnFail true
+ -htmlOutFile <htmlOutFile>                 Html out file result optional (E.g: result.html)
+ -jsonOutFile <jsonOutFile>                 Json out file result optional (E.g: result.json)
+ -junitFile <junitFile>                     JUnit XML file name out (Always created, default: TEST-jmeter-junit-plugin-jmreport.xml)
+ -kpiFile <kpiFile>                         KPI file contains rule to check (E.g: kpi.csv)
+E.g : java -jar junit-reporter-kpi-from-jmeter-report-csv-<version>-jar-with-dependencies.jar -csvJMReport summary.csv  -kpiFile kpi.csv
+-exitReturnOnFail true
+or more parameters : java -jar junit-reporter-kpi-from-jmeter-report-csv-<version>-jar-with-dependencies.jar -csvJMReport
+AggregateReport.csv  -csvLabelColumnName Label -kpiFile kpi_check.csv -junitFile junit.xml -htmlOutFile result.html -divHtmlOutFile
+div_result.html -csvOutFile result.csv -jsonOutFile result.json -exitReturnOnFail false
 
## JUnit Report XML file generated @@ -95,6 +103,18 @@ A JUnit Report with KPIs display in Jenkins Build
If you click on link "Name Test" fail , you will show the fail message
![junit jenkins build detail fail](doc/images/junit_report_jenkins_detail_fail.png) +## Html out format +The result could be a html page ou partial html page (div) +![html out format](doc/images/html_out_result.png) + +## Csv out format +The result in a csv file +![csv out format](doc/images/csv_out_result.png) + +## Json out format +The result in a Json file +![csv out format](doc/images/json_out_result.png) + ## License See the LICENSE file Apache 2 [https://www.apache.org/licenses/LICENSE-2.0](https://www.apache.org/licenses/LICENSE-2.0) @@ -104,7 +124,7 @@ The maven groupId, artifactId and version, this plugin is in the **Maven Central ```xml io.github.vdaburon junit-reporter-kpi-from-jmeter-report-csv -1.3 +1.4 ``` Just include the plugin in your `pom.xml` and execute `mvn verify`
or individual launch `mvn -DjmeterReportFile=synthesis.csv -DkpiFile=kpi.csv -DjunitFile=jmeter-junit-plugin-jmreport.xml exec:java@create_junit-report-kpi-from-jmeter-report` @@ -122,7 +142,7 @@ or individual launch `mvn -DjmeterReportFile=synthesis.csv -DkpiFile=kpi.csv -Dj io.github.vdaburon junit-reporter-kpi-from-jmeter-report-csv - 1.3 + 1.4 @@ -170,6 +190,8 @@ java -jar junit-reporter-kpi-from-jmeter-report-csv-<version>-jar-with-dep Usually this plugin is use with [jmeter-graph-tool-maven-plugin](https://github.com/vdaburon/jmeter-graph-tool-maven-plugin) ## Versions +version 1.4 export result in html, json or csv format + Version 1.3 change Fail Message when Equality Version 1.2 change package name (add reportkpi) diff --git a/doc/images/csv_out_result.png b/doc/images/csv_out_result.png new file mode 100644 index 0000000..e8d7311 Binary files /dev/null and b/doc/images/csv_out_result.png differ diff --git a/doc/images/html_out_result.png b/doc/images/html_out_result.png new file mode 100644 index 0000000..39f642f Binary files /dev/null and b/doc/images/html_out_result.png differ diff --git a/doc/images/json_out_result.png b/doc/images/json_out_result.png new file mode 100644 index 0000000..fab308b Binary files /dev/null and b/doc/images/json_out_result.png differ diff --git a/pom.xml b/pom.xml index 4917cad..ccec51b 100644 --- a/pom.xml +++ b/pom.xml @@ -6,10 +6,10 @@ io.github.vdaburon junit-reporter-kpi-from-jmeter-report-csv - 1.3 + 1.4 jar Create a JUnit XML file with KPI rules from JMeter CSV Report - A tool that creates a JUnit XML file with KPI rules from JMeter CSV Report + A tool that creates a JUnit XML file with KPI rules from JMeter CSV Report, export result in html, csv or json format https://github.com/vdaburon/JUnitReportKpiJMeterReportCsv 2023 @@ -64,16 +64,34 @@ + + + commons-cli + commons-cli + 1.5.0 + + + org.apache.commons commons-csv 1.10.0 + + + + org.freemarker + freemarker + 2.3.32 + + + - commons-cli - commons-cli - 1.5.0 + com.fasterxml.jackson.core + jackson-databind + 2.15.2 + diff --git a/src/main/java/io/github/vdaburon/jmeter/utils/reportkpi/CheckKpiResult.java b/src/main/java/io/github/vdaburon/jmeter/utils/reportkpi/CheckKpiResult.java index ecc03cb..1c2d8d7 100644 --- a/src/main/java/io/github/vdaburon/jmeter/utils/reportkpi/CheckKpiResult.java +++ b/src/main/java/io/github/vdaburon/jmeter/utils/reportkpi/CheckKpiResult.java @@ -53,6 +53,10 @@ public boolean isKpiFail() { return isKpiFail; } + public boolean getKpiFail() { + return isKpiFail; + } + public void setKpiFail(boolean kpiFail) { isKpiFail = kpiFail; } diff --git a/src/main/java/io/github/vdaburon/jmeter/utils/reportkpi/GlobalResult.java b/src/main/java/io/github/vdaburon/jmeter/utils/reportkpi/GlobalResult.java new file mode 100644 index 0000000..0fa4253 --- /dev/null +++ b/src/main/java/io/github/vdaburon/jmeter/utils/reportkpi/GlobalResult.java @@ -0,0 +1,63 @@ +package io.github.vdaburon.jmeter.utils.reportkpi; + +import java.util.List; + +public class GlobalResult { + private String csvJmeterReport; + private String kpiFile; + private int numberOfKpis; + private int numberFailed; + List checkKpiResults; + + public String getCsvJmeterReport() { + return csvJmeterReport; + } + + public void setCsvJmeterReport(String csvJmeterReport) { + this.csvJmeterReport = csvJmeterReport; + } + + public String getKpiFile() { + return kpiFile; + } + + public void setKpiFile(String kpiFile) { + this.kpiFile = kpiFile; + } + + public int getNumberOfKpis() { + return numberOfKpis; + } + + public void setNumberOfKpis(int numberOfKpis) { + this.numberOfKpis = numberOfKpis; + } + + public int getNumberFailed() { + return numberFailed; + } + + public void setNumberFailed(int numberFailed) { + this.numberFailed = numberFailed; + } + + public List getCheckKpiResults() { + return checkKpiResults; + } + + public void setCheckKpiResults(List checkKpiResults) { + this.checkKpiResults = checkKpiResults; + } + + @Override + public String toString() { + final StringBuilder sb = new StringBuilder("GlobalResult{"); + sb.append("csvJmeterReport='").append(csvJmeterReport).append('\''); + sb.append(", kpiFile='").append(kpiFile).append('\''); + sb.append(", numberOfKpis=").append(numberOfKpis); + sb.append(", numberFailed=").append(numberFailed); + sb.append(", checkKpiResults=").append(checkKpiResults); + sb.append('}'); + return sb.toString(); + } +} diff --git a/src/main/java/io/github/vdaburon/jmeter/utils/reportkpi/JUnitReportFromJMReportCsv.java b/src/main/java/io/github/vdaburon/jmeter/utils/reportkpi/JUnitReportFromJMReportCsv.java index d6a6440..d1772ef 100644 --- a/src/main/java/io/github/vdaburon/jmeter/utils/reportkpi/JUnitReportFromJMReportCsv.java +++ b/src/main/java/io/github/vdaburon/jmeter/utils/reportkpi/JUnitReportFromJMReportCsv.java @@ -1,11 +1,14 @@ package io.github.vdaburon.jmeter.utils.reportkpi; import java.io.IOException; +import java.io.PrintWriter; +import java.io.StringWriter; import java.util.*; import java.util.logging.Logger; import java.util.regex.Matcher; import java.util.regex.Pattern; +import freemarker.template.TemplateException; import org.apache.commons.cli.CommandLine; import org.apache.commons.cli.CommandLineParser; import org.apache.commons.cli.DefaultParser; @@ -24,13 +27,23 @@ public class JUnitReportFromJMReportCsv { private static final Logger LOGGER = Logger.getLogger(JUnitReportFromJMReportCsv.class.getName()); + + // System.exit return public static final int K_RETURN_OK = 0; public static final int K_RETURN_KO = 1; - public static final String K_JUNIT_XML_FILE_DEFAULT = "jmeter-junit-plugin-jmreport.xml"; + + // Defaut JUnit XML Report file + public static final String K_JUNIT_XML_FILE_DEFAULT = "TEST-jmeter-junit-plugin-jmreport.xml"; + + // OPTions for Command Line Parameters public static final String K_CVS_JM_REPORT_OPT = "csvJMReport"; public static final String K_CSV_LABEL_COLUMN_NAME_OPT = "csvLabelColumnName"; public static final String K_KPI_FILE_OPT = "kpiFile"; public static final String K_JUNIT_XML_FILE_OPT = "junitFile"; + public static final String K_OUT_HTML_FILE_OPT = "htmlOutFile"; + public static final String K_OUT_DIV_HTML_FILE_OPT = "divHtmlOutFile"; + public static final String K_OUT_CSV_FILE_OPT = "csvOutFile"; + public static final String K_OUT_JSON_FILE_OPT = "jsonOutFile"; public static final String K_EXIT_RETURN_ON_FAIL_OPT = "exitReturnOnFail"; @@ -41,10 +54,22 @@ public class JUnitReportFromJMReportCsv { public static final String K_CSV_COL_COMPARATOR = "comparator"; public static final String K_CSV_COL_THREASHOLD = "threshold"; + // Column name for Html or CSV out file + public static final String K_CSV_COL_OUT_RESULT = "result"; + public static final String K_CSV_COL_OUT_FAIL_MSG = "fail_msg"; + + private static final String K_NOT_SET = "NOT SET"; - // column name Label in jmeter csv report + // Column name Label in jmeter csv report public static final String K_CSV_JMREPORT_COL_LABEL_DEFAULT = "Label"; + // Freemarker Html Template + public static final String K_FREEMARKER_HTML_TEMPLATE_DIRECTORY = "/templates_freemarker"; + public static final String K_FREEMARKER_HTML_TEMPLATE = "template_html_result.ftl"; + public static final String K_FREEMARKER_DIV_HTML_TEMPLATE = "template_div_result.ftl"; + + public static final int K_TYPE_HTML_TEMPLATE = 1; + public static final int K_TYPE_DIV_HTML_TEMPLATE = 2; public static final int K_FAIL_MESSAGE_SIZE_MAX = 1024; public static void main(String[] args) { @@ -61,10 +86,15 @@ public static void main(String[] args) { } int exitReturn = K_RETURN_KO; - String csvJmeterReport = "NOT SET"; + String csvJmeterReport = K_NOT_SET; String csvLabelColumnName = K_CSV_JMREPORT_COL_LABEL_DEFAULT; - String kpiFile = "NOT SET"; + String kpiFile = K_NOT_SET; String junitFile = K_JUNIT_XML_FILE_DEFAULT; + String htmlFile = K_NOT_SET; + String divHtmlFile = K_NOT_SET; + String csvFile = K_NOT_SET; + String jsonFile = K_NOT_SET; + boolean exitOnFailKpi = false; String sTmp; @@ -88,6 +118,26 @@ public static void main(String[] args) { junitFile = sTmp; } + sTmp = (String) parseProperties.get(K_OUT_HTML_FILE_OPT); + if (sTmp != null && sTmp.length() > 1) { + htmlFile = sTmp; + } + + sTmp = (String) parseProperties.get(K_OUT_DIV_HTML_FILE_OPT); + if (sTmp != null && sTmp.length() > 1) { + divHtmlFile = sTmp; + } + + sTmp = (String) parseProperties.get(K_OUT_CSV_FILE_OPT); + if (sTmp != null && sTmp.length() > 1) { + csvFile = sTmp; + } + + sTmp = (String) parseProperties.get(K_OUT_JSON_FILE_OPT); + if (sTmp != null && sTmp.length() > 1) { + jsonFile = sTmp; + } + sTmp = (String) parseProperties.get(K_EXIT_RETURN_ON_FAIL_OPT); if (sTmp != null) { exitOnFailKpi = Boolean.parseBoolean(sTmp); @@ -95,13 +145,16 @@ public static void main(String[] args) { } boolean isKpiFail = false; LOGGER.info("Parameters CLI:" + parseProperties); + try { - isKpiFail = analyseCsvJMReportWithKpiRules(csvJmeterReport,csvLabelColumnName, kpiFile, junitFile); + isKpiFail = analyseCsvJMReportWithKpiRules(csvJmeterReport, csvLabelColumnName, kpiFile, junitFile, htmlFile, divHtmlFile, csvFile, jsonFile); LOGGER.info("isKpiFail=" + isKpiFail); } catch (Exception ex) { - LOGGER.warning(ex.toString()); + LOGGER.warning(stackTraceInString(ex)); + isKpiFail = true; exitReturn = K_RETURN_KO; } + if (exitOnFailKpi && isKpiFail) { // at least one kpi rule failure => exit 1 exitReturn = K_RETURN_KO; @@ -109,6 +162,7 @@ public static void main(String[] args) { } else { exitReturn = K_RETURN_OK; } + long endTimeMs = System.currentTimeMillis(); LOGGER.info("Duration ms=" + (endTimeMs - startTimeMs)); LOGGER.info("End main (exit " + exitReturn + ")"); @@ -118,20 +172,31 @@ public static void main(String[] args) { /** * Analyse the kpi verifications on JMeter report values - * @param csvJmeterReport the JMeter Report CSV format + * + * @param csvJmeterReport the JMeter Report CSV format * @param csvLabelColumnName the Label Column Name (default : Label) - * @param kpiFile the kpi contains kpi declaration - * @param junitFile the JUnit XML out file to create + * @param kpiFile the kpi contains kpi declaration + * @param junitFile the JUnit XML out file to create + * @param htmlFile the Html out file result optional + * @param divHtmlFile partial Div Html out file result optional + * @param csvFile the Cvs out file result optional + * @param jsonFile the Json out file result optional * @return is Fail true or false, a kpi is fail or not - * @throws IOException file exception + * @throws IOException file exception * @throws ParserConfigurationException error reading csv file - * @throws TransformerException error writing JUnit XML file + * @throws TransformerException error writing JUnit XML file */ - private static boolean analyseCsvJMReportWithKpiRules(String csvJmeterReport, String csvLabelColumnName, String kpiFile, String junitFile) throws IOException, ParserConfigurationException, TransformerException { + private static boolean analyseCsvJMReportWithKpiRules(String csvJmeterReport, String csvLabelColumnName, String kpiFile, String junitFile, String htmlFile, String divHtmlFile, String csvFile, String jsonFile) throws IOException, ParserConfigurationException, TransformerException, TemplateException { boolean isFail = false; List csvJMReportLines = UtilsCsvFile.readCsvFile(csvJmeterReport); List csvKpiLines = UtilsCsvFile.readCsvFile(kpiFile); + GlobalResult globalResult = new GlobalResult(); + List checkKpiResults = new ArrayList<>(); + globalResult.setCheckKpiResults(checkKpiResults); + globalResult.setCsvJmeterReport(csvJmeterReport); + globalResult.setKpiFile(kpiFile); + int nbFailed = 0; Document document = UtilsJUnitXml.createJUnitRootDocument(); for (int i = 0; i < csvKpiLines.size(); i++) { CSVRecord recordKpiLine = csvKpiLines.get(i); @@ -141,22 +206,47 @@ private static boolean analyseCsvJMReportWithKpiRules(String csvJmeterReport, St CheckKpiResult checkKpiResult = verifyKpi(recordKpiLine, csvJMReportLines, csvLabelColumnName); if (checkKpiResult.isKpiFail()) { isFail = true; - String className = checkKpiResult.getMetricCsvColumnName() + " (" + checkKpiResult.getLabelRegex() + ") " + checkKpiResult.getComparator() + " " + checkKpiResult.getThreshold(); - UtilsJUnitXml.addTestCaseFailure(document,checkKpiResult.getNameKpi(), className, checkKpiResult.getFailMessage()); + nbFailed++; + String className = checkKpiResult.getMetricCsvColumnName() + " (" + checkKpiResult.getLabelRegex() + ") " + checkKpiResult.getComparator() + " " + checkKpiResult.getThreshold(); + UtilsJUnitXml.addTestCaseFailure(document, checkKpiResult.getNameKpi(), className, checkKpiResult.getFailMessage()); } else { - String className = checkKpiResult.getMetricCsvColumnName() + " (" + checkKpiResult.getLabelRegex() + ") " + checkKpiResult.getComparator() + " " + checkKpiResult.getThreshold(); - UtilsJUnitXml.addTestCaseOk(document,checkKpiResult.getNameKpi(), className); + String className = checkKpiResult.getMetricCsvColumnName() + " (" + checkKpiResult.getLabelRegex() + ") " + checkKpiResult.getComparator() + " " + checkKpiResult.getThreshold(); + UtilsJUnitXml.addTestCaseOk(document, checkKpiResult.getNameKpi(), className); } + globalResult.getCheckKpiResults().add(checkKpiResult); } + globalResult.setNumberOfKpis(csvKpiLines.size()); + globalResult.setNumberFailed(nbFailed); + LOGGER.info("Write junitFile=" + junitFile); - UtilsJUnitXml.saveXmlInFile(document, junitFile); + UtilsJUnitXml.saveXmFile(document, junitFile); + if (!K_NOT_SET.equals(htmlFile)) { + LOGGER.info("Write html file=" + htmlFile); + UtilsHtml.saveHtmlFile(globalResult, htmlFile, K_TYPE_HTML_TEMPLATE); + } + + if (!K_NOT_SET.equals(divHtmlFile)) { + LOGGER.info("Write Div Html file=" + divHtmlFile); + UtilsHtml.saveHtmlFile(globalResult, divHtmlFile, K_TYPE_DIV_HTML_TEMPLATE); + } + + if (!K_NOT_SET.equals(csvFile)) { + LOGGER.info("Write csv file=" + csvFile); + UtilsCsvFile.saveCsvFile(globalResult, csvFile); + } + + if (!K_NOT_SET.equals(jsonFile)) { + LOGGER.info("Write json file=" + jsonFile); + UtilsJsonFile.saveJsonFile(globalResult, jsonFile); + } return isFail; } /** * verify one kpi for lines in csv JMeter Report - * @param recordKpiLine a kpi line to verify - * @param csvJMReportLines all lines in JMeter Report + * + * @param recordKpiLine a kpi line to verify + * @param csvJMReportLines all lines in JMeter Report * @param csvLabelColumnName the Label Column name in the JMeter Report (usually : Label) * @return the result of the kpi verification and the failure message if kpi fail */ @@ -178,16 +268,16 @@ private static CheckKpiResult verifyKpi(CSVRecord recordKpiLine, List checkKpiResult.setThreshold(threshold.trim()); checkKpiResult.setKpiFail(false); - checkKpiResult.setFailMessage("NOT SET"); + checkKpiResult.setFailMessage(""); - Pattern patternRegex = Pattern.compile(labelRegex) ; + Pattern patternRegex = Pattern.compile(labelRegex); boolean isFailKpi = false; boolean isFirstFail = true; for (int i = 0; i < csvJMReportLines.size(); i++) { CSVRecord recordJMReportLine = csvJMReportLines.get(i); String label = recordJMReportLine.get(csvLabelColumnName); - Matcher matcherRegex = patternRegex.matcher(label) ; + Matcher matcherRegex = patternRegex.matcher(label); if (matcherRegex.matches()) { String sMetric = recordJMReportLine.get(metricCsvColumnName); LOGGER.fine("sMetric=<" + sMetric + ">"); @@ -214,18 +304,12 @@ private static CheckKpiResult verifyKpi(CSVRecord recordKpiLine, List isFailKpi = true; if (isFirstFail) { isFirstFail = false; - String failMessage = "Actual value " + dMetric + " exceeds or equals threshold " + dThreshold + " for samples matching \"" + labelRegex + "\"; fail label(s) \"" + label + "\""; // Actual value 2908,480000 exceeds threshold 2500,000000 for samples matching "@SC01_P03_DUMMY" + String failMessage = "Actual value " + dMetric + " exceeds or equals threshold " + dThreshold + " for samples matching \"" + labelRegex + "\"; fail label(s) \"" + label + "\""; // Actual value 2908,480000 exceeds threshold 2500,000000 for samples matching "@SC01_P03_DUMMY" checkKpiResult.setKpiFail(true); checkKpiResult.setFailMessage(failMessage); } else { String failMessage = checkKpiResult.getFailMessage(); - if ((failMessage.length() + label.length()) < K_FAIL_MESSAGE_SIZE_MAX) { - failMessage += ", \"" + label + "\""; - } else { - if (!failMessage.endsWith(" ...")) { - failMessage += " ..."; - } - } + failMessage = concatFailMessage(label, failMessage); checkKpiResult.setFailMessage(failMessage); } } @@ -242,13 +326,7 @@ private static CheckKpiResult verifyKpi(CSVRecord recordKpiLine, List checkKpiResult.setFailMessage(failMessage); } else { String failMessage = checkKpiResult.getFailMessage(); - if ((failMessage.length() + label.length()) < K_FAIL_MESSAGE_SIZE_MAX) { - failMessage += ", \"" + label + "\""; - } else { - if (!failMessage.endsWith(" ...")) { - failMessage += " ..."; - } - } + failMessage = concatFailMessage(label, failMessage); checkKpiResult.setFailMessage(failMessage); } } @@ -265,13 +343,7 @@ private static CheckKpiResult verifyKpi(CSVRecord recordKpiLine, List checkKpiResult.setFailMessage(failMessage); } else { String failMessage = checkKpiResult.getFailMessage(); - if ((failMessage.length() + label.length()) < K_FAIL_MESSAGE_SIZE_MAX) { - failMessage += ", \"" + label + "\""; - } else { - if (!failMessage.endsWith(" ...")) { - failMessage += " ..."; - } - } + failMessage = concatFailMessage(label, failMessage); checkKpiResult.setFailMessage(failMessage); } } @@ -288,13 +360,7 @@ private static CheckKpiResult verifyKpi(CSVRecord recordKpiLine, List checkKpiResult.setFailMessage(failMessage); } else { String failMessage = checkKpiResult.getFailMessage(); - if ((failMessage.length() + label.length()) < K_FAIL_MESSAGE_SIZE_MAX) { - failMessage += ", \"" + label + "\""; - } else { - if (!failMessage.endsWith(" ...")) { - failMessage += " ..."; - } - } + failMessage = concatFailMessage(label, failMessage); checkKpiResult.setFailMessage(failMessage); } } @@ -307,6 +373,23 @@ private static CheckKpiResult verifyKpi(CSVRecord recordKpiLine, List return checkKpiResult; } + private static String concatFailMessage(String label, String failMessage) { + if ((failMessage.length() + label.length()) < K_FAIL_MESSAGE_SIZE_MAX) { + failMessage += ", \"" + label + "\""; + } else { + if (!failMessage.endsWith(" ...")) { + failMessage += " ..."; + } + } + return failMessage; + } + + private static String stackTraceInString(Exception ex) { + StringWriter sw = new StringWriter(); + PrintWriter pw = new PrintWriter(sw); + ex.printStackTrace(pw); + return sw.toString(); + } /** * If incorrect parameter or help, display usage * @param options options and cli parameters @@ -316,7 +399,8 @@ private static void helpUsage(Options options) { String footer = "E.g : java -jar junit-reporter-kpi-from-jmeter-report-csv--jar-with-dependencies.jar -" + K_CVS_JM_REPORT_OPT + " summary.csv -" + K_KPI_FILE_OPT + " kpi.csv -" + K_EXIT_RETURN_ON_FAIL_OPT + " true\n"; footer += "or more parameters : java -jar junit-reporter-kpi-from-jmeter-report-csv--jar-with-dependencies.jar -" + K_CVS_JM_REPORT_OPT + " AggregateReport.csv -" - + K_CSV_LABEL_COLUMN_NAME_OPT + " Label -" + K_KPI_FILE_OPT + " kpi_check.csv -" + K_JUNIT_XML_FILE_OPT + " junit.xml -" + K_EXIT_RETURN_ON_FAIL_OPT + " true\n"; + + K_CSV_LABEL_COLUMN_NAME_OPT + " Label -" + K_KPI_FILE_OPT + " kpi_check.csv -" + K_JUNIT_XML_FILE_OPT + " junit.xml -" + + K_OUT_HTML_FILE_OPT + " result.html -" + K_OUT_DIV_HTML_FILE_OPT + " div_result.html -" + K_OUT_CSV_FILE_OPT + " result.csv -" + K_OUT_JSON_FILE_OPT + " result.json -" + K_EXIT_RETURN_ON_FAIL_OPT + " false\n"; formatter.printHelp(140, JUnitReportFromJMReportCsv.class.getName(), JUnitReportFromJMReportCsv.class.getName(), options, footer, true); } @@ -360,6 +444,22 @@ private static Properties parseOption(Options optionsP, String[] args) throws Pa properties.setProperty(K_JUNIT_XML_FILE_OPT, line.getOptionValue(K_JUNIT_XML_FILE_OPT)); } + if (line.hasOption(K_OUT_HTML_FILE_OPT)) { + properties.setProperty(K_OUT_HTML_FILE_OPT, line.getOptionValue(K_OUT_HTML_FILE_OPT)); + } + + if (line.hasOption(K_OUT_DIV_HTML_FILE_OPT)) { + properties.setProperty(K_OUT_DIV_HTML_FILE_OPT, line.getOptionValue(K_OUT_DIV_HTML_FILE_OPT)); + } + + if (line.hasOption(K_OUT_CSV_FILE_OPT)) { + properties.setProperty(K_OUT_CSV_FILE_OPT, line.getOptionValue(K_OUT_CSV_FILE_OPT)); + } + + if (line.hasOption(K_OUT_JSON_FILE_OPT)) { + properties.setProperty(K_OUT_JSON_FILE_OPT, line.getOptionValue(K_OUT_JSON_FILE_OPT)); + } + if (line.hasOption(K_EXIT_RETURN_ON_FAIL_OPT)) { properties.setProperty(K_EXIT_RETURN_ON_FAIL_OPT, line.getOptionValue(K_EXIT_RETURN_ON_FAIL_OPT)); } @@ -380,35 +480,63 @@ private static Options createOptions() { Option csvJmeterReportFileOpt = Option.builder(K_CVS_JM_REPORT_OPT).argName(K_CVS_JM_REPORT_OPT) .hasArg(true) .required(true) - .desc("JMeter report csv file (E.g : summary.csv or aggregate.csv or synthesis.csv)") + .desc("JMeter report csv file (E.g: summary.csv or aggregate.csv or synthesis.csv)") .build(); options.addOption(csvJmeterReportFileOpt); Option csvLabelColumnNameOpt = Option.builder(K_CSV_LABEL_COLUMN_NAME_OPT).argName(K_CSV_LABEL_COLUMN_NAME_OPT) .hasArg(true) .required(false) - .desc("Label Column Name in CSV JMeter Report (Default : " + K_CSV_JMREPORT_COL_LABEL_DEFAULT + ")") + .desc("Label Column Name in CSV JMeter Report (Default: " + K_CSV_JMREPORT_COL_LABEL_DEFAULT + ")") .build(); options.addOption(csvLabelColumnNameOpt); Option kpiFileOpt = Option.builder(K_KPI_FILE_OPT).argName(K_KPI_FILE_OPT) .hasArg(true) .required(true) - .desc("KPI file contains rule to check (E.g : kpi.csv)") + .desc("KPI file contains rule to check (E.g: kpi.csv)") .build(); options.addOption(kpiFileOpt); Option junitXmlOutOpt = Option.builder(K_JUNIT_XML_FILE_OPT).argName(K_JUNIT_XML_FILE_OPT) .hasArg(true) .required(false) - .desc("junit file name out (Default : " + K_JUNIT_XML_FILE_DEFAULT + ")") + .desc("JUnit XML file name out (Always created, default: " + K_JUNIT_XML_FILE_DEFAULT + ")") .build(); options.addOption(junitXmlOutOpt); + Option htmlOutOpt = Option.builder(K_OUT_HTML_FILE_OPT).argName(K_OUT_HTML_FILE_OPT) + .hasArg(true) + .required(false) + .desc("Html out file result optional (E.g: result.html)") + .build(); + options.addOption(htmlOutOpt); + + Option divHtmlOutOpt = Option.builder(K_OUT_DIV_HTML_FILE_OPT).argName(K_OUT_DIV_HTML_FILE_OPT) + .hasArg(true) + .required(false) + .desc("Div Partial Html Page out file result optional (E.g: div_result.html), to include in an another HTML Page") + .build(); + options.addOption(divHtmlOutOpt); + + Option csvOutOpt = Option.builder(K_OUT_CSV_FILE_OPT).argName(K_OUT_CSV_FILE_OPT) + .hasArg(true) + .required(false) + .desc("Csv out file result optional (E.g: result.csv)") + .build(); + options.addOption(csvOutOpt); + + Option jsonOutOpt = Option.builder(K_OUT_JSON_FILE_OPT).argName(K_OUT_JSON_FILE_OPT) + .hasArg(true) + .required(false) + .desc("Json out file result optional (E.g: result.json)") + .build(); + options.addOption(jsonOutOpt); + Option exitReturnOnFailOpt = Option.builder(K_EXIT_RETURN_ON_FAIL_OPT).argName(K_EXIT_RETURN_ON_FAIL_OPT) .hasArg(true) .required(false) - .desc("if true then when kpi fail then create JUnit XML file and program return exit 1 (KO); if false (Default) then create JUnit XML File and exit 0 (OK)") + .desc("If true then when kpi fail then create JUnit XML file and program return exit 1 (KO); If false (Default) then create JUnit XML File and exit 0 (OK)") .build(); options.addOption(exitReturnOnFailOpt); diff --git a/src/main/java/io/github/vdaburon/jmeter/utils/reportkpi/UtilsCsvFile.java b/src/main/java/io/github/vdaburon/jmeter/utils/reportkpi/UtilsCsvFile.java index 14a139c..6344aac 100644 --- a/src/main/java/io/github/vdaburon/jmeter/utils/reportkpi/UtilsCsvFile.java +++ b/src/main/java/io/github/vdaburon/jmeter/utils/reportkpi/UtilsCsvFile.java @@ -1,9 +1,13 @@ package io.github.vdaburon.jmeter.utils.reportkpi; import org.apache.commons.csv.CSVFormat; +import org.apache.commons.csv.CSVPrinter; import org.apache.commons.csv.CSVRecord; -import java.io.*; +import java.io.FileReader; +import java.io.FileWriter; +import java.io.IOException; +import java.io.Reader; import java.util.ArrayList; import java.util.List; @@ -26,4 +30,39 @@ public static List readCsvFile(String fileIn) throws IOException { in.close(); return listRecordsBetweenFirstAndLast; } + + /** + * Write the KPIs Lines Result in a CSV file ( + * @param globalResult Global KPIs result + * @param csvFile Csv out file result + * @throws IOException + */ + public static void saveCsvFile(GlobalResult globalResult, String csvFile) throws IOException { + String[] headers = { + JUnitReportFromJMReportCsv.K_CSV_COL_NAME_KPI, + JUnitReportFromJMReportCsv.K_CSV_LABEL_COLUMN_NAME_OPT, + JUnitReportFromJMReportCsv.K_CSV_COL_LABEL_REGEX, + JUnitReportFromJMReportCsv.K_CSV_COL_COMPARATOR, + JUnitReportFromJMReportCsv.K_CSV_COL_THREASHOLD, + JUnitReportFromJMReportCsv.K_CSV_COL_OUT_RESULT, + JUnitReportFromJMReportCsv.K_CSV_COL_OUT_FAIL_MSG + }; + + FileWriter fileWrite = new FileWriter(csvFile); + + CSVFormat csvFormat = CSVFormat.RFC4180.builder() + .setHeader(headers) + .build(); + List checkKpiResults = globalResult.getCheckKpiResults(); + CSVPrinter printer = new CSVPrinter(fileWrite, csvFormat); + for (int i = 0; i < checkKpiResults.size(); i++) { + CheckKpiResult checkKpiResult = (CheckKpiResult) checkKpiResults.get(i); + String sResult = checkKpiResult.isKpiFail()?"fail":"sucess"; + String sFailMessage = checkKpiResult.getFailMessage() != null?checkKpiResult.getFailMessage():""; + + printer.printRecord(checkKpiResult.getNameKpi(), checkKpiResult.getMetricCsvColumnName(), checkKpiResult.getLabelRegex(), checkKpiResult.getComparator(), + checkKpiResult.getThreshold(), sResult, sFailMessage); + } + printer.close(); + } } diff --git a/src/main/java/io/github/vdaburon/jmeter/utils/reportkpi/UtilsFile.java b/src/main/java/io/github/vdaburon/jmeter/utils/reportkpi/UtilsFile.java new file mode 100644 index 0000000..5317b96 --- /dev/null +++ b/src/main/java/io/github/vdaburon/jmeter/utils/reportkpi/UtilsFile.java @@ -0,0 +1,19 @@ +package io.github.vdaburon.jmeter.utils.reportkpi; + +import java.io.BufferedWriter; +import java.io.IOException; +import java.nio.charset.StandardCharsets; +import java.nio.file.Files; +import java.nio.file.Path; +import java.nio.file.Paths; + +public class UtilsFile { + + public static void writeFileUtf8(String fileName, String toWrite) throws java.io.IOException { + Path path = Paths.get(fileName); + BufferedWriter writer = Files.newBufferedWriter(path, StandardCharsets.UTF_8); + writer.append(toWrite); + writer.newLine(); + writer.close(); + } +} diff --git a/src/main/java/io/github/vdaburon/jmeter/utils/reportkpi/UtilsHtml.java b/src/main/java/io/github/vdaburon/jmeter/utils/reportkpi/UtilsHtml.java new file mode 100644 index 0000000..8019b50 --- /dev/null +++ b/src/main/java/io/github/vdaburon/jmeter/utils/reportkpi/UtilsHtml.java @@ -0,0 +1,70 @@ +package io.github.vdaburon.jmeter.utils.reportkpi; + +import freemarker.core.HTMLOutputFormat; +import freemarker.template.Configuration; +import freemarker.template.Template; +import freemarker.template.TemplateException; +import freemarker.template.TemplateExceptionHandler; +import freemarker.template.Version; + +import java.io.File; +import java.io.FileWriter; +import java.io.IOException; +import java.io.Writer; +import java.util.HashMap; +import java.util.Locale; +import java.util.Map; + +public class UtilsHtml { + + private static Configuration cfg = null; + + /** + * Initialise the Freemarker Template Engine for Html result + * @throws IOException + */ + public static void init() throws IOException { + cfg = new Configuration(); + cfg.setClassForTemplateLoading(UtilsHtml.class, JUnitReportFromJMReportCsv.K_FREEMARKER_HTML_TEMPLATE_DIRECTORY); + + cfg.setIncompatibleImprovements(new Version(2, 3, 22)); + cfg.setDefaultEncoding("UTF-8"); + cfg.setLocale(Locale.US); + cfg.setOutputFormat(HTMLOutputFormat.INSTANCE); + cfg.setTemplateExceptionHandler(TemplateExceptionHandler.RETHROW_HANDLER); + + } + + /** + * Write the Global KPIs Result in a Html format + * @param globalResult contains the KPIs results + * @param htmlFileOut Html out file result + * @throws IOException can write the file + * @throws TemplateException can read the template freemaker file + */ + public static void saveHtmlFile(GlobalResult globalResult, String htmlFileOut, int typeTemplate) throws IOException, TemplateException { + if (cfg == null) { + init(); + } + Template template = null; + if (typeTemplate == JUnitReportFromJMReportCsv.K_TYPE_HTML_TEMPLATE) { + template = cfg.getTemplate(JUnitReportFromJMReportCsv.K_FREEMARKER_HTML_TEMPLATE); + } + + if (typeTemplate == JUnitReportFromJMReportCsv.K_TYPE_DIV_HTML_TEMPLATE) { + template = cfg.getTemplate(JUnitReportFromJMReportCsv.K_FREEMARKER_DIV_HTML_TEMPLATE); + } + + Map root = new HashMap<>(); + root.put("globalResult", globalResult); + Writer fileWriter = new FileWriter(new File(htmlFileOut)); + try { + template.process(root, fileWriter); + } finally { + fileWriter.close(); + } + + } + +} + diff --git a/src/main/java/io/github/vdaburon/jmeter/utils/reportkpi/UtilsJUnitXml.java b/src/main/java/io/github/vdaburon/jmeter/utils/reportkpi/UtilsJUnitXml.java index 272e6aa..ef9bd7f 100644 --- a/src/main/java/io/github/vdaburon/jmeter/utils/reportkpi/UtilsJUnitXml.java +++ b/src/main/java/io/github/vdaburon/jmeter/utils/reportkpi/UtilsJUnitXml.java @@ -15,11 +15,14 @@ import javax.xml.transform.stream.StreamResult; import java.io.File; +import java.util.logging.Logger; + /** * Utility Class to create a JUnit DOM, add testcase and write JUnit XML file */ public class UtilsJUnitXml { + private static final Logger LOGGER = Logger.getLogger(UtilsJUnitXml.class.getName()); /** * Create the DOM for a JUnit XML file * @return the DOM with testsuite root element @@ -149,7 +152,7 @@ public static void addTestCaseFailure(Document document, String classname, Stri * @param junitXmlFileOut XML file to write * @throws TransformerException error when write XML file */ - public static void saveXmlInFile(Document document, String junitXmlFileOut) throws TransformerException { + public static void saveXmFile(Document document, String junitXmlFileOut) throws TransformerException { // create the xml file //transform the DOM Object to an XML File TransformerFactory transformerFactory = TransformerFactory.newInstance(); @@ -160,4 +163,5 @@ public static void saveXmlInFile(Document document, String junitXmlFileOut) thro StreamResult streamResult = new StreamResult(new File(junitXmlFileOut)); transformer.transform(domSource, streamResult); } + } diff --git a/src/main/java/io/github/vdaburon/jmeter/utils/reportkpi/UtilsJsonFile.java b/src/main/java/io/github/vdaburon/jmeter/utils/reportkpi/UtilsJsonFile.java new file mode 100644 index 0000000..241ddf2 --- /dev/null +++ b/src/main/java/io/github/vdaburon/jmeter/utils/reportkpi/UtilsJsonFile.java @@ -0,0 +1,16 @@ +package io.github.vdaburon.jmeter.utils.reportkpi; + +import com.fasterxml.jackson.databind.ObjectMapper; +import com.fasterxml.jackson.databind.SerializationFeature; +import freemarker.template.TemplateException; + +import java.io.File; +import java.io.IOException; + +public class UtilsJsonFile { + public static void saveJsonFile(GlobalResult globalResult, String jsonFileOut) throws IOException, TemplateException { + ObjectMapper objectMapper = new ObjectMapper(); + objectMapper.enable(SerializationFeature.INDENT_OUTPUT); + objectMapper.writeValue(new File(jsonFileOut), globalResult); + } +} diff --git a/src/main/resources/templates_freemarker/template_div_result.ftl b/src/main/resources/templates_freemarker/template_div_result.ftl new file mode 100644 index 0000000..6d95389 --- /dev/null +++ b/src/main/resources/templates_freemarker/template_div_result.ftl @@ -0,0 +1,41 @@ +
+ +

HTML KPIs Result From JMeter Report Csv

+

Files In

+ + + +
File with KPIs${globalResult.kpiFile}
File CSV Report${globalResult.csvJmeterReport}
+
+

Test Summary

+ + + +
Number of failed testsstyle="color:Red;bold">${globalResult.numberFailed}
Number of tests${globalResult.numberOfKpis}
+
+

Table KPIs Results

+ + + <#list globalResult.checkKpiResults as checkKpiResult> + + + + + + + + + + +
name_kpimetric_csv_column_namelabel_regexcomparatorthresholdresultfail_msg
${checkKpiResult.nameKpi}${checkKpiResult.metricCsvColumnName}${checkKpiResult.labelRegex}${checkKpiResult.comparator}${checkKpiResult.threshold}<#if checkKpiResult.kpiFail>fail<#else>sucess<#if checkKpiResult.kpiFail>${checkKpiResult.failMessage}
+