Added in durations and fixed unicode bug when parsing

This commit is contained in:
Kingsley Hendrickse 2012-04-27 15:51:46 +01:00
parent 161ea375f0
commit 979abc7b1e
11 changed files with 174 additions and 75 deletions

View File

@ -39,6 +39,7 @@
<orderEntry type="library" scope="TEST" name="Maven: junit:junit:4.8.2" level="project" />
<orderEntry type="library" name="Maven: antlr:antlr:2.7.5" level="project" />
<orderEntry type="library" name="Maven: com.jamesmurty.utils:java-xmlbuilder:0.4" level="project" />
<orderEntry type="library" name="Maven: joda-time:joda-time:2.1" level="project" />
<orderEntry type="library" scope="TEST" name="Maven: org.jenkins-ci.main:jenkins-war:war:1.424" level="project" />
<orderEntry type="library" scope="PROVIDED" name="Maven: org.jenkins-ci.main:jenkins-core:1.424" level="project" />
<orderEntry type="library" scope="PROVIDED" name="Maven: org.jenkins-ci.main:remoting:2.4" level="project" />

View File

@ -10,7 +10,7 @@
<groupId>net.masterthought.jenkins</groupId>
<artifactId>cucumber-reports</artifactId>
<version>0.0.3</version>
<version>0.0.5</version>
<packaging>hpi</packaging>
<!-- get every artifact through repo.jenkins-ci.org, which proxies all the artifacts that we need -->
@ -49,5 +49,10 @@
<artifactId>java-xmlbuilder</artifactId>
<version>0.4</version>
</dependency>
<dependency>
<groupId>joda-time</groupId>
<artifactId>joda-time</artifactId>
<version>2.1</version>
</dependency>
</dependencies>
</project>

View File

@ -1,6 +1,7 @@
package net.masterthought.jenkins;
import com.google.gson.Gson;
import com.google.gson.GsonBuilder;
import net.masterthought.jenkins.json.Element;
import net.masterthought.jenkins.json.Feature;
import net.masterthought.jenkins.json.Step;
@ -8,10 +9,15 @@ import net.masterthought.jenkins.json.Util;
import org.apache.velocity.Template;
import org.apache.velocity.VelocityContext;
import org.apache.velocity.app.VelocityEngine;
import org.joda.time.Period;
import org.joda.time.format.PeriodFormatter;
import org.joda.time.format.PeriodFormatterBuilder;
import java.io.*;
import java.text.SimpleDateFormat;
import java.util.*;
import java.util.regex.Matcher;
import java.util.regex.Pattern;
public class FeatureReportGenerator {
@ -22,6 +28,7 @@ public class FeatureReportGenerator {
private List<Util.Status> totalSteps;
private String pluginUrlPath;
private List<Feature> allFeatures;
private static final String charEncoding = "UTF-8";
public FeatureReportGenerator(List<String> jsonResultFiles, File reportDirectory, String pluginUrlPath, String buildNumber, String buildProject) throws IOException {
this.jsonResultFiles = parseJsonResults(jsonResultFiles);
@ -33,11 +40,12 @@ public class FeatureReportGenerator {
this.pluginUrlPath = getPluginUrlPath(pluginUrlPath);
}
private Map<String, List<Feature>> parseJsonResults(List<String> jsonResultFiles) throws FileNotFoundException {
private Map<String, List<Feature>> parseJsonResults(List<String> jsonResultFiles) throws IOException {
Map<String, List<Feature>> featureResults = new HashMap<String, List<Feature>>();
for (String jsonFile : jsonResultFiles) {
FileReader reader = new FileReader(jsonFile);
featureResults.put(jsonFile, Arrays.asList(new Gson().fromJson(reader, Feature[].class)));
String fileContent = U2U(Util.readFileAsString(jsonFile));
Feature[] features = new Gson().fromJson(fileContent, Feature[].class);
featureResults.put(jsonFile, Arrays.asList(features));
}
return featureResults;
}
@ -63,11 +71,12 @@ public class FeatureReportGenerator {
context.put("total_skipped", getTotalSkipped());
context.put("chart_data", XmlChartBuilder.donutChart(getTotalPasses(), getTotalFails(), getTotalSkipped()));
context.put("time_stamp", timeStamp());
context.put("total_duration", getTotalDuration());
context.put("jenkins_base", pluginUrlPath);
generateReport("feature-overview.html", featureOverview, context);
}
private List<Feature> listAllFeatures(){
private List<Feature> listAllFeatures() {
List<Feature> allFeatures = new ArrayList<Feature>();
Iterator it = jsonResultFiles.entrySet().iterator();
while (it.hasNext()) {
@ -77,7 +86,7 @@ public class FeatureReportGenerator {
}
return allFeatures;
}
public void generateFeatureReports() throws Exception {
Iterator it = jsonResultFiles.entrySet().iterator();
@ -100,10 +109,19 @@ public class FeatureReportGenerator {
generateReport(feature.getFileName(), featureResult, context);
}
}
}
private static final Pattern p = Pattern.compile("\\\\u\\s*([0-9(A-F|a-f)]{4})", Pattern.MULTILINE);
public static String U2U(String s) {
String res = s;
Matcher m = p.matcher(res);
while (m.find()) {
res = res.replaceAll("\\" + m.group(0),
Character.toString((char) Integer.parseInt(m.group(1), 16)));
}
return res;
}
private String getPluginUrlPath(String path) {
return path.isEmpty() ? "/" : path;
@ -113,6 +131,18 @@ public class FeatureReportGenerator {
return totalSteps.size();
}
private String getTotalDuration() {
Long duration = 0L;
for (Feature feature : allFeatures) {
for (Element scenario : feature.getElements()) {
for (Step step : scenario.getSteps()) {
duration = duration + step.getDuration();
}
}
}
return Util.formatDuration(duration);
}
private int getTotalPasses() {
return Util.findStatusCount(totalSteps, Util.Status.PASSED);
}
@ -167,11 +197,6 @@ public class FeatureReportGenerator {
return feature.getStatus() == Util.Status.PASSED ? "#C5D88A" : "#D88A8A";
}
// private List<Feature> parseJson(String jsonResultFile) throws FileNotFoundException {
// FileReader reader = new FileReader(jsonResultFile);
// return Arrays.asList(new Gson().fromJson(reader, Feature[].class));
// }
private String timeStamp() {
return new SimpleDateFormat("dd-MM-yyyy HH:mm:ss").format(new Date());
}

View File

@ -1,20 +1,22 @@
//package net.masterthought.jenkins;
//
//
//import java.io.File;
//import java.util.ArrayList;
//import java.util.List;
//
//public class Runner {
//
// public static void main(String[] args) throws Exception {
// File rd = new File("/Users/kings/.jenkins/jobs/aaaaa/builds/3/cucumber-html-reports");
// List<String> list = new ArrayList<String>();
// list.add("/Users/kings/.jenkins/jobs/aaaaa/builds/3/cucumber-html-reports/ss_cucumber.json");
// list.add("/Users/kings/.jenkins/jobs/aaaaa/builds/3/cucumber-html-reports/co_cucumber.json");
//
// FeatureReportGenerator featureReportGenerator = new FeatureReportGenerator(list,rd,"","3","aaaa");
// featureReportGenerator.generateReports();
//
// }
//}
package net.masterthought.jenkins;
import java.io.File;
import java.util.ArrayList;
import java.util.List;
public class Runner {
public static void main(String[] args) throws Exception {
File rd = new File("/Users/kings/.jenkins/jobs/aaaaa/builds/15/cucumber-html-reports");
List<String> list = new ArrayList<String>();
list.add("/Users/kings/.jenkins/jobs/aaaaa/builds/15/cucumber-html-reports/french.json");
list.add("/Users/kings/.jenkins/jobs/aaaaa/builds/15/cucumber-html-reports/co_cucumber.json");
list.add("/Users/kings/.jenkins/jobs/aaaaa/builds/15/cucumber-html-reports/ccp_cucumber.json");
list.add("/Users/kings/.jenkins/jobs/aaaaa/builds/15/cucumber-html-reports/ss_cucumber.json");
FeatureReportGenerator featureReportGenerator = new FeatureReportGenerator(list,rd,"","15","aaaa");
featureReportGenerator.generateReports();
}
}

View File

@ -89,6 +89,16 @@ public class Feature {
public String getRawStatus() {
return getStatus().toString().toLowerCase();
}
public String getDurationOfSteps(){
Long totalDuration = 0L;
for(Element element : elements){
for(Step step : element.getSteps()){
totalDuration = totalDuration + step.getDuration();
}
}
return Util.formatDuration(totalDuration);
}
}

View File

@ -4,9 +4,9 @@ public class Result {
private String status;
private String error_message;
private int duration;
private Long duration;
public Result(String status, String error_message, int duration){
public Result(String status, String error_message, Long duration){
this.status = status;
this.error_message = error_message;
this.duration = duration;
@ -16,6 +16,10 @@ public class Result {
return status;
}
public Long getDuration(){
return duration == null ? 0L : duration;
}
public String getErrorMessage(){
return error_message;
}

View File

@ -15,14 +15,6 @@ public class Step {
this.keyword = keyword;
}
// public Row getTitleRow(){
// return rows[0];
// }
// public List getRows(){
// return Arrays.asList(rows).subList(1, -1);
// }
public Row[] getRows(){
return rows;
@ -38,6 +30,10 @@ public class Step {
return result;
}
public Long getDuration(){
return result.getDuration();
}
public Util.Status getStatus() {
return Util.resultMap.get(result.getStatus());
}

View File

@ -3,7 +3,16 @@ package net.masterthought.jenkins.json;
import net.masterthought.jenkins.json.Closure;
import net.masterthought.jenkins.json.Element;
import net.masterthought.jenkins.json.Step;
import org.joda.time.DateTime;
import org.joda.time.Duration;
import org.joda.time.Period;
import org.joda.time.format.PeriodFormatter;
import org.joda.time.format.PeriodFormatterBuilder;
import java.io.BufferedInputStream;
import java.io.File;
import java.io.FileInputStream;
import java.io.IOException;
import java.util.ArrayList;
import java.util.HashMap;
import java.util.List;
@ -35,22 +44,25 @@ public class Util {
put("passed", Util.Status.PASSED);
put("failed", Util.Status.FAILED);
put("skipped", Util.Status.SKIPPED);
put("undefined", Util.Status.UNDEFINED);
}};
public static String result(Status status) {
String result = "";
String result = "<div>";
if (status == Status.PASSED) {
result = "<div class=\"passed\">";
} else if (status == Status.FAILED) {
result = "<div class=\"failed\">";
} else if (status == Status.SKIPPED) {
result = "<div class=\"skipped\">";
} else if (status == Status.UNDEFINED){
result = "<div class=\"undefined\">";
}
return result;
}
public static enum Status {
PASSED, FAILED, SKIPPED
PASSED, FAILED, SKIPPED, UNDEFINED
}
public static <T, R> List<R> collectScenarios(Element[] list, Closure<String, Element> clo) {
@ -90,4 +102,41 @@ public class Util {
}
return occurrence;
}
public static String readFileAsString(String filePath) throws java.io.IOException {
byte[] buffer = new byte[(int) new File(filePath).length()];
BufferedInputStream f = null;
try {
f = new BufferedInputStream(new FileInputStream(filePath));
f.read(buffer);
} finally {
if (f != null) try {
f.close();
} catch (IOException ignored) {
}
}
return new String(buffer);
}
public static String formatDuration(Long duration){
PeriodFormatter formatter = new PeriodFormatterBuilder()
.appendDays()
.appendSuffix(" day", " days")
.appendSeparator(" and ")
.appendHours()
.appendSuffix(" hour", " hours")
.appendSeparator(" and ")
.appendMinutes()
.appendSuffix(" min", " mins")
.appendSeparator(" and ")
.appendSeconds()
.appendSuffix(" sec", " secs")
.appendSeparator(" and ")
.appendMillis()
.appendSuffix(" ms", " ms")
.toFormatter();
return formatter.print(new Period(0, duration/1000000));
}
}

View File

@ -33,6 +33,7 @@ var requiredRevision = 45;
.passed{background-color:#C5D88A;}
.failed{background-color:#D88A8A;}
.skipped{background-color:#2DEAEC;}
.undefined{background-color: #ebcc81;}
table.stats-table {
color:black;
@ -86,7 +87,7 @@ table.stats-table td {
</div>
<div class="container_12">
<div class="grid_9">
<div class="grid_12">
<div style="text-align:center;"><script language="JavaScript" type="text/javascript">
<!--
if (AC_FL_RunContent == 0 || DetectFlashVer == 0) {
@ -142,6 +143,7 @@ if (AC_FL_RunContent == 0 || DetectFlashVer == 0) {
<th>Passed</th>
<th>Failed</th>
<th>Skipped</th>
<th>Duration</th>
<th>Status</th>
</tr>
@ -154,12 +156,13 @@ if (AC_FL_RunContent == 0 || DetectFlashVer == 0) {
#end
<tr>
<td><a href="$feature.getFileName()">$feature.getRawName()</a></td>
<td style="text-align:left;"><a href="$feature.getFileName()">$feature.getRawName()</a></td>
<td>$feature.getNumberOfScenarios()</td>
<td>$feature.getNumberOfSteps()</td>
<td>$feature.getNumberOfPasses()</td>
<td>$feature.getNumberOfFailures()</td>
<td>$feature.getNumberOfSkipped()</td>
<td>$feature.getDurationOfSteps()</td>
<td style="background-color: $bgcolour;">$feature.getRawStatus()</td>
</tr>
#end
@ -171,6 +174,7 @@ if (AC_FL_RunContent == 0 || DetectFlashVer == 0) {
<td style="background-color:lightgray;font-weight:bold;">$total_passes</td>
<td style="background-color:lightgray;font-weight:bold;">$total_fails</td>
<td style="background-color:lightgray;font-weight:bold;">$total_skipped</td>
<td style="background-color:lightgray;font-weight:bold;">$total_duration</td>
<td style="background-color:lightgray;font-weight:bold;">Totals</td>
</tr></table>
</div>

View File

@ -23,6 +23,7 @@
.passed{background-color:#C5D88A;}
.failed{background-color:#D88A8A;}
.skipped{background-color:#2DEAEC;}
.undefined{background-color: #ebcc81;}
table.stats-table {
color:black;
@ -151,6 +152,7 @@ table.data-table td {
<th>Passed</th>
<th>Failed</th>
<th>Skipped</th>
<th>Duration</th>
<th>Status</th>
</tr>
@ -161,6 +163,7 @@ table.data-table td {
<td>$feature.getNumberOfPasses()</td>
<td>$feature.getNumberOfFailures()</td>
<td>$feature.getNumberOfSkipped()</td>
<td>$feature.getDurationOfSteps()</td>
<td style="background-color: $report_status_colour;">$feature.getRawStatus()</td></tr>
</table>

View File

@ -1,28 +1,28 @@
Thu Apr 19 10:59:24 BST 2012 [debug] AvalonLogChute initialized using file 'velocity.log'
Thu Apr 19 10:59:24 BST 2012 [trace] *******************************************************************
Thu Apr 19 10:59:24 BST 2012 [debug] Starting Jakarta Velocity v1.5-SNAPSHOT (compiled: 2006-07-21 06:25:35)
Thu Apr 19 10:59:24 BST 2012 [trace] RuntimeInstance initializing.
Thu Apr 19 10:59:24 BST 2012 [debug] Default Properties File: org/apache/velocity/runtime/defaults/velocity.properties
Thu Apr 19 10:59:24 BST 2012 [debug] Trying to use logger class org.apache.velocity.runtime.log.AvalonLogChute
Thu Apr 19 10:59:24 BST 2012 [debug] Using logger class org.apache.velocity.runtime.log.AvalonLogChute
Thu Apr 19 10:59:24 BST 2012 [debug] Default ResourceManager initializing. (class org.apache.velocity.runtime.resource.ResourceManagerImpl)
Thu Apr 19 10:59:24 BST 2012 [debug] ResourceLoader instantiated: org.apache.velocity.runtime.resource.loader.ClasspathResourceLoader
Thu Apr 19 10:59:24 BST 2012 [trace] ClasspathResourceLoader : initialization complete.
Thu Apr 19 10:59:24 BST 2012 [debug] ResourceCache: initialized (class org.apache.velocity.runtime.resource.ResourceCacheImpl)
Thu Apr 19 10:59:24 BST 2012 [trace] Default ResourceManager initialization complete.
Thu Apr 19 10:59:24 BST 2012 [debug] Loaded System Directive: org.apache.velocity.runtime.directive.Literal
Thu Apr 19 10:59:24 BST 2012 [debug] Loaded System Directive: org.apache.velocity.runtime.directive.Macro
Thu Apr 19 10:59:24 BST 2012 [debug] Loaded System Directive: org.apache.velocity.runtime.directive.Parse
Thu Apr 19 10:59:24 BST 2012 [debug] Loaded System Directive: org.apache.velocity.runtime.directive.Include
Thu Apr 19 10:59:24 BST 2012 [debug] Loaded System Directive: org.apache.velocity.runtime.directive.Foreach
Thu Apr 19 10:59:24 BST 2012 [debug] Created '20' parsers.
Thu Apr 19 10:59:24 BST 2012 [trace] Velocimacro : initialization starting.
Thu Apr 19 10:59:24 BST 2012 [debug] Velocimacro : "velocimacro.library" is not set. Trying default library: VM_global_library.vm
Thu Apr 19 10:59:24 BST 2012 [debug] Velocimacro : Default library not found.
Thu Apr 19 10:59:24 BST 2012 [debug] Velocimacro : allowInline = true : VMs can be defined inline in templates
Thu Apr 19 10:59:24 BST 2012 [debug] Velocimacro : allowInlineToOverride = false : VMs defined inline may NOT replace previous VM definitions
Thu Apr 19 10:59:24 BST 2012 [debug] Velocimacro : allowInlineLocal = false : VMs defined inline will be global in scope if allowed.
Thu Apr 19 10:59:24 BST 2012 [debug] Velocimacro : autoload off : VM system will not automatically reload global library macros
Thu Apr 19 10:59:24 BST 2012 [trace] Velocimacro : initialization complete.
Thu Apr 19 10:59:24 BST 2012 [trace] RuntimeInstance successfully initialized.
Thu Apr 19 10:59:24 BST 2012 [debug] ResourceManager : found templates/featureOverview.vm with loader org.apache.velocity.runtime.resource.loader.ClasspathResourceLoader
Fri Apr 27 15:48:26 BST 2012 [debug] AvalonLogChute initialized using file 'velocity.log'
Fri Apr 27 15:48:26 BST 2012 [trace] *******************************************************************
Fri Apr 27 15:48:26 BST 2012 [debug] Starting Jakarta Velocity v1.5-SNAPSHOT (compiled: 2006-07-21 06:25:35)
Fri Apr 27 15:48:26 BST 2012 [trace] RuntimeInstance initializing.
Fri Apr 27 15:48:26 BST 2012 [debug] Default Properties File: org/apache/velocity/runtime/defaults/velocity.properties
Fri Apr 27 15:48:26 BST 2012 [debug] Trying to use logger class org.apache.velocity.runtime.log.AvalonLogChute
Fri Apr 27 15:48:26 BST 2012 [debug] Using logger class org.apache.velocity.runtime.log.AvalonLogChute
Fri Apr 27 15:48:26 BST 2012 [debug] Default ResourceManager initializing. (class org.apache.velocity.runtime.resource.ResourceManagerImpl)
Fri Apr 27 15:48:26 BST 2012 [debug] ResourceLoader instantiated: org.apache.velocity.runtime.resource.loader.ClasspathResourceLoader
Fri Apr 27 15:48:26 BST 2012 [trace] ClasspathResourceLoader : initialization complete.
Fri Apr 27 15:48:26 BST 2012 [debug] ResourceCache: initialized (class org.apache.velocity.runtime.resource.ResourceCacheImpl)
Fri Apr 27 15:48:26 BST 2012 [trace] Default ResourceManager initialization complete.
Fri Apr 27 15:48:26 BST 2012 [debug] Loaded System Directive: org.apache.velocity.runtime.directive.Literal
Fri Apr 27 15:48:26 BST 2012 [debug] Loaded System Directive: org.apache.velocity.runtime.directive.Macro
Fri Apr 27 15:48:26 BST 2012 [debug] Loaded System Directive: org.apache.velocity.runtime.directive.Parse
Fri Apr 27 15:48:26 BST 2012 [debug] Loaded System Directive: org.apache.velocity.runtime.directive.Include
Fri Apr 27 15:48:26 BST 2012 [debug] Loaded System Directive: org.apache.velocity.runtime.directive.Foreach
Fri Apr 27 15:48:26 BST 2012 [debug] Created '20' parsers.
Fri Apr 27 15:48:26 BST 2012 [trace] Velocimacro : initialization starting.
Fri Apr 27 15:48:26 BST 2012 [debug] Velocimacro : "velocimacro.library" is not set. Trying default library: VM_global_library.vm
Fri Apr 27 15:48:26 BST 2012 [debug] Velocimacro : Default library not found.
Fri Apr 27 15:48:26 BST 2012 [debug] Velocimacro : allowInline = true : VMs can be defined inline in templates
Fri Apr 27 15:48:26 BST 2012 [debug] Velocimacro : allowInlineToOverride = false : VMs defined inline may NOT replace previous VM definitions
Fri Apr 27 15:48:26 BST 2012 [debug] Velocimacro : allowInlineLocal = false : VMs defined inline will be global in scope if allowed.
Fri Apr 27 15:48:26 BST 2012 [debug] Velocimacro : autoload off : VM system will not automatically reload global library macros
Fri Apr 27 15:48:26 BST 2012 [trace] Velocimacro : initialization complete.
Fri Apr 27 15:48:26 BST 2012 [trace] RuntimeInstance successfully initialized.
Fri Apr 27 15:48:27 BST 2012 [debug] ResourceManager : found templates/featureOverview.vm with loader org.apache.velocity.runtime.resource.loader.ClasspathResourceLoader