Skip to content

Commit

Permalink
HTML Report: Using gzip to compress generated scenario data (fixes #186)
Browse files Browse the repository at this point in the history
  • Loading branch information
Jan Schäfer committed Feb 5, 2016
1 parent 2bcab2c commit 1411e8a
Show file tree
Hide file tree
Showing 6 changed files with 69 additions and 24 deletions.
8 changes: 8 additions & 0 deletions CHANGELOG.md
Original file line number Diff line number Diff line change
@@ -1,3 +1,11 @@
# v0.11.1

## New Features

### HTML Report size reduction

* The size of the HTML report has been greatly reduced by compressing the scenario data with gzip. This significantly reduces the load time of large reports on slow network connections. [#186](https://github.com/TNG/JGiven/pull/186)

# v0.11.0

## New Features
Expand Down
4 changes: 1 addition & 3 deletions jgiven-html5-report/bower.json
Original file line number Diff line number Diff line change
Expand Up @@ -33,8 +33,6 @@
"angular-local-storage": "0.1.5",
"angular-mocks": "1.4.8",
"angular-bindonce": "0.3.3",
"datatables.net": "~1.10.10",
"datatables.net-dt": "~1.10.10",
"datatables.net-zf": "~1.10.10"
"pako":"0.2.8"
}
}
3 changes: 1 addition & 2 deletions jgiven-html5-report/build.gradle
Original file line number Diff line number Diff line change
Expand Up @@ -63,8 +63,7 @@ task copyJsFiles(type: Copy) {
include '**/angular-local-storage.js'
include '**/mm-foundation-tpls.min.js'
include 'angular-bindonce/bindonce.min.js'
include 'datatables.net/js/jquery.dataTables.min.js'
include 'datatables.net-zf/js/dataTables.foundation.min.js'
include 'pako/dist/pako_inflate.min.js'
into appDir + 'js'
includeEmptyDirs = false
eachFile { details ->
Expand Down
3 changes: 1 addition & 2 deletions jgiven-html5-report/src/app/index.html
Original file line number Diff line number Diff line change
Expand Up @@ -692,8 +692,7 @@ <h6 class="cases-table-header">Cases
<script src="js/angular-local-storage.js"></script>
<script src="js/bindonce.min.js"></script>
<script src="js/lodash.min.js"></script>
<script src="js/jquery.dataTables.min.js"></script>
<script src="js/dataTables.foundation.min.js"></script>
<script src="js/pako_inflate.min.js"></script>
<script src="lib/util.js"></script>
<script src="lib/app.js"></script>
<script src="lib/offCanvasDirective.js"></script>
Expand Down
6 changes: 6 additions & 0 deletions jgiven-html5-report/src/app/lib/api.js
Original file line number Diff line number Diff line change
Expand Up @@ -19,6 +19,12 @@ var jgivenReport = {
});
},

addZippedScenarios: function addZippedScenarios (zip) {
var string = pako.ungzip(atob(zip), {to: 'string'})
var unzipped = JSON.parse(string);
this.addScenarios(unzipped.scenarios);
},

addScenarios: function addScenarios (scenarios) {
this.scenarios = this.scenarios.concat(scenarios);
},
Expand Down
Original file line number Diff line number Diff line change
@@ -1,11 +1,15 @@
package com.tngtech.jgiven.report.html5;

import java.io.*;
import java.util.Collections;
import java.util.Date;
import java.util.List;
import java.util.zip.GZIPOutputStream;
import java.util.zip.ZipEntry;
import java.util.zip.ZipInputStream;

import javax.xml.bind.DatatypeConverter;

import org.slf4j.Logger;
import org.slf4j.LoggerFactory;

Expand All @@ -16,18 +20,18 @@
import com.google.gson.Gson;
import com.tngtech.jgiven.impl.util.ResourceUtil;
import com.tngtech.jgiven.report.AbstractReportGenerator;
import com.tngtech.jgiven.report.model.ReportModel;
import com.tngtech.jgiven.report.model.ReportModelFile;
import com.tngtech.jgiven.report.model.ScenarioModel;
import com.tngtech.jgiven.report.model.*;

public class Html5ReportGenerator extends AbstractReportGenerator {
private static final Logger log = LoggerFactory.getLogger( Html5ReportGenerator.class );
private static final int MAX_BATCH_SIZE = 100;

private PrintStream writer;
private PrintStream fileStream;
private MetaData metaData = new MetaData();
private int caseCountOfCurrentBatch;
private File dataDirectory;
private ByteArrayOutputStream byteStream;
private PrintStream contentStream;

@Override
public void generate() {
Expand Down Expand Up @@ -60,31 +64,53 @@ private void copyCustomFile( File file, File targetDirectory, String targetName
}
}

private void createDataFiles() {
private void createDataFiles() throws IOException {
for( ReportModelFile file : completeReportModel.getAllReportModels() ) {
handleReportModel( file.model, file.file );
}
closeWriter();
}

public void handleReportModel( ReportModel model, File file ) {
public void handleReportModel( ReportModel model, File file ) throws IOException {
new Html5AttachmentGenerator().generateAttachments( dataDirectory, model );

createWriter();

if( caseCountOfCurrentBatch > 0 ) {
contentStream.append( "," );
}

deleteUnusedCaseSteps( model );
caseCountOfCurrentBatch += getCaseCount( model );

// do not serialize tags as they are serialized separately
model.setTagMap( null );

new Gson().toJson( model, writer );
writer.append( "," );
new Gson().toJson( model, contentStream );

if( caseCountOfCurrentBatch > MAX_BATCH_SIZE ) {
closeWriter();
}
}

/**
* Deletes all steps of scenario cases where a data table
* is generated to reduce the size of the data file.
* In this case only the steps of the first scenario case are actually needed.
*/
private void deleteUnusedCaseSteps( ReportModel model ) {

for( ScenarioModel scenarioModel : model.getScenarios() ) {
if( scenarioModel.isCasesAsTable() ) {
List<ScenarioCaseModel> cases = scenarioModel.getScenarioCases();
for( int i = 1; i < cases.size(); i++ ) {
ScenarioCaseModel caseModel = cases.get( i );
caseModel.setSteps( Collections.<StepModel>emptyList() );
}
}
}
}

private int getCaseCount( ReportModel model ) {

int count = 0;
Expand All @@ -94,27 +120,36 @@ private int getCaseCount( ReportModel model ) {
return count;
}

private void closeWriter() {
if( writer != null ) {
this.writer.append( "]);" );
writer.flush();
ResourceUtil.close( writer );
writer = null;
private void closeWriter() throws IOException {
if( fileStream != null ) {
contentStream.append( "]}" );
contentStream.flush();
ResourceUtil.close( contentStream );
String base64String = DatatypeConverter.printBase64Binary( byteStream.toByteArray() );
this.fileStream.append( "'" + base64String + "'" );
this.fileStream.append( ");" );
fileStream.flush();
ResourceUtil.close( fileStream );
fileStream = null;
log.info( "Written " + caseCountOfCurrentBatch + " scenarios to " + metaData.data.get( metaData.data.size() - 1 ) );
}
}

private void createWriter() {
if( this.writer == null ) {
if( this.fileStream == null ) {
String fileName = "data" + metaData.data.size() + ".js";
metaData.data.add( fileName );
File targetFile = new File( dataDirectory, fileName );
log.debug( "Generating " + targetFile + "..." );
caseCountOfCurrentBatch = 0;

try {
this.writer = new PrintStream( new FileOutputStream( targetFile ), false, "utf-8" );
this.writer.append( "jgivenReport.addScenarios([" );
this.byteStream = new ByteArrayOutputStream();
this.contentStream = new PrintStream( new GZIPOutputStream( byteStream ) );
this.contentStream.append( "{\"scenarios\":[" );

this.fileStream = new PrintStream( new FileOutputStream( targetFile ), false, "utf-8" );
this.fileStream.append( "jgivenReport.addZippedScenarios(" );
} catch( Exception e ) {
throw new RuntimeException( "Could not open file " + targetFile + " for writing", e );
}
Expand Down

0 comments on commit 1411e8a

Please sign in to comment.