From 93eb66e951a33bd2ad05eb6f3d5270459edf5e01 Mon Sep 17 00:00:00 2001 From: Timo Tijhof Date: Sun, 24 Jun 2018 20:52:56 +0100 Subject: [PATCH 1/2] build: Update dev dependencies MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit eslint-config-wikimedia 0.3.0 → 0.5.0 grunt 1.0.2 → 1.0.3 grunt-contrib-watch 1.0.0 → 1.1.0 grunt-eslint 18.0.0 → 20.2.0 grunt-jsonlint 1.0.8 → 1.1.0 grunt-eslint has a newer version (21.0) that requires Node 6, given we still support Node 4, staying on the latest before it. --- package.json | 10 +++++----- 1 file changed, 5 insertions(+), 5 deletions(-) diff --git a/package.json b/package.json index 4e1b087..75a886a 100644 --- a/package.json +++ b/package.json @@ -25,10 +25,10 @@ }, "dependencies": {}, "devDependencies": { - "eslint-config-wikimedia": "0.3.0", - "grunt": "1.0.2", - "grunt-contrib-watch": "1.0.0", - "grunt-eslint": "18.0.0", - "grunt-jsonlint": "1.0.8" + "eslint-config-wikimedia": "0.5.0", + "grunt": "1.0.3", + "grunt-contrib-watch": "1.1.0", + "grunt-eslint": "20.2.0", + "grunt-jsonlint": "1.1.0" } } From 14a71110dd6bbd2a42cb1cf300736bb18efc0f78 Mon Sep 17 00:00:00 2001 From: Timo Tijhof Date: Sun, 24 Jun 2018 22:37:35 +0100 Subject: [PATCH 2/2] test: Add benchmarks Uses the same fixtures as the benchmarks for php-cssjanus. --- .gitignore | 1 + .travis.yml | 1 + test/bench.js | 149 ++++++++++++++++++++++++++++++++++++++++++++++++++ 3 files changed, 151 insertions(+) create mode 100644 test/bench.js diff --git a/.gitignore b/.gitignore index 846af48..2d23b67 100644 --- a/.gitignore +++ b/.gitignore @@ -1,2 +1,3 @@ /dest /node_modules +/test/fixture*.dat diff --git a/.travis.yml b/.travis.yml index 75b2392..60a703c 100644 --- a/.travis.yml +++ b/.travis.yml @@ -4,6 +4,7 @@ node_js: - "8" - "6" - "4" +after_success: node test/bench notifications: irc: channels: diff --git a/test/bench.js b/test/bench.js new file mode 100644 index 0000000..e30d714 --- /dev/null +++ b/test/bench.js @@ -0,0 +1,149 @@ +/* eslint one-var:["error","never"], no-console:"off" */ +/* global Promise */ +var crypto = require( 'crypto' ); +var fs = require( 'fs' ); +var https = require( 'https' ); +var cssjanus = require( '../' ); + +var baseBench = { + name: '', + started: NaN, + start: function ( name ) { + this.name = name; + this.started = process.hrtime(); + }, + end: function ( ops ) { + var time; + var rate; + var elapsed = process.hrtime( this.started ); + if ( elapsed[ 0 ] === 0 && elapsed[ 1 ] === 0 ) { + throw new Error( 'insufficient clock precision for short benchmark' ); + } + time = elapsed[ 0 ] + elapsed[ 1 ] / 1e9; + rate = ops / time; + this.report( rate, time ); + }, + report: function ( rate, time ) { + console.log( 'Bench ' + this.name + + ': ' + rate.toFixed( 0 ) + ' op/s in ' + + time.toFixed( 1 ) + 's' + ); + } +}; + +function checksum( algorithm, str ) { + return crypto + .createHash( algorithm ) + .update( str, 'utf8' ) + .digest( 'hex' ); +} + +function fetch( url ) { + var redirects = 0; + return new Promise( function ( resolve, reject ) { + https.get( url, function handleResponse( res ) { + var data = ''; + // Handle redirect + if ( res.statusCode === 301 || res.statusCode === 302 ) { + if ( !res.headers.location ) { + reject( new Error( 'Redirect without location' ) ); + return; + } + redirects++; + if ( redirects > 1 ) { + reject( new Error( 'Too many redirects' ) ); + return; + } + https.get( res.headers.location, handleResponse ); + res.resume(); + return; + } + // Handle http error + if ( res.statusCode !== 200 ) { + reject( new Error( 'HTTP ' + res.statusCode ) ); + res.resume(); + return; + } + res.setEncoding( 'utf8' ); + res.on( 'data', function ( chunk ) { + data += chunk; + } ); + res.on( 'end', function () { + resolve( data ); + } ); + } ).on( 'end', function ( err ) { + reject( err ); + } ); + } ); +} + +function getFixture( name, sha1, url ) { + var data; + var pData; + var fetched; + var file = __dirname + '/fixture.' + name + '.dat'; + try { + data = fs.readFileSync( file, 'utf8' ); + if ( checksum( 'sha1', data ) !== sha1 ) { + fetched = true; + pData = fetch( url ); + } else { + // re-use cached fixture + pData = Promise.resolve( data ); + } + } catch ( e ) { + fetched = true; + pData = fetch( url ); + } + return pData.then( function ( data ) { + if ( fetched ) { + if ( checksum( 'sha1', data ) !== sha1 ) { + return Promise.reject( new Error( 'Checksum mis-match' ) ); + } + fs.writeFileSync( file, data ); + } + return data; + } ); +} + +function benchFixture( fixture ) { + return getFixture( fixture.name, fixture.sha1, fixture.src ) + .then( function ( data ) { + var ops = 1000; + var i = ops; + var bench = Object.create( baseBench ); + bench.start( fixture.name ); + while ( i-- ) { + cssjanus.transform( data ); + } + bench.end( ops ); + } ); +} + +function benchFixtures() { + var fixtures = [ + { + name: 'mediawiki', + sha1: '6277eb6b3ce25e2abcaa720f5da1b979686ea166', + src: 'https://github.com/wikimedia/mediawiki/raw/1064426/resources/src/mediawiki.legacy/shared.css' + }, + { + name: 'ooui', + sha1: 'b6f7ebc0e26c53617284d3f3a99552f9ffbf85fa', + src: 'https://github.com/wikimedia/mediawiki/raw/130344b/resources/lib/oojs-ui/oojs-ui-core-wikimediaui.css' + } + ]; + function next( fixture ) { + return benchFixture( fixture ).then( function () { + if ( fixtures[ 0 ] ) { + return next( fixtures.shift() ); + } + } ); + } + return next( fixtures.shift() ); +} + +benchFixtures().catch( function ( err ) { + console.error( err ); + process.exit( 1 ); +} );