Implements a general score calculator

This commit is contained in:
Gaël Métais
2014-12-14 15:47:58 +01:00
parent 8abfe93df7
commit 792f7d8e21
11 changed files with 478 additions and 20 deletions
+202 -8
View File
@@ -8,25 +8,30 @@ var config = {
}
};
var apiUrl = 'http://localhost:8387/api';
var serverUrl = 'http://localhost:8387';
var wwwUrl = 'http://localhost:8388';
describe('api', function() {
var runId;
var syncRunResultUrl;
var asyncRunId;
var apiServer;
// Start the server
before(function(done) {
apiServer = require('../../bin/server.js');
apiServer.startTests = done;
});
it('should refuse a query with an invalid key', function(done) {
this.timeout(5000);
request({
method: 'POST',
url: apiUrl + '/runs',
url: serverUrl + '/api/runs',
body: {
url: wwwUrl + '/simple-page.html',
waitForResponse: false
@@ -44,12 +49,67 @@ describe('api', function() {
});
});
it('should accept a query with a valid key', function(done) {
it('should launch a synchronous run', function(done) {
this.timeout(15000);
request({
method: 'POST',
url: serverUrl + '/api/runs',
body: {
url: wwwUrl + '/simple-page.html',
waitForResponse: true
},
json: true,
headers: {
'X-Api-Key': Object.keys(config.authorizedKeys)[0]
}
}, function(error, response, body) {
if (!error && response.statusCode === 302) {
response.headers.should.have.a.property('location').that.is.a('string');
syncRunResultUrl = response.headers.location;
done();
} else {
done(error || response.statusCode);
}
});
});
it('should retrieve the results for the synchronous run', function(done) {
this.timeout(15000);
request({
method: 'GET',
url: serverUrl + syncRunResultUrl,
json: true,
}, function(error, response, body) {
if (!error && response.statusCode === 200) {
body.should.have.a.property('runId').that.is.a('string');
body.should.have.a.property('params').that.is.an('object');
body.should.have.a.property('scoreProfiles').that.is.an('object');
body.should.have.a.property('rules').that.is.an('object');
body.should.have.a.property('toolsResults').that.is.an('object');
body.should.have.a.property('javascriptExecutionTree').that.is.an('object');
done();
} else {
done(error || response.statusCode);
}
});
});
it('should launch a run without waiting for the response', function(done) {
this.timeout(5000);
request({
method: 'POST',
url: apiUrl + '/runs',
url: serverUrl + '/api/runs',
body: {
url: wwwUrl + '/simple-page.html',
waitForResponse: false
@@ -61,8 +121,35 @@ describe('api', function() {
}, function(error, response, body) {
if (!error && response.statusCode === 200) {
runId = body.runId;
runId.should.be.a('string');
asyncRunId = body.runId;
asyncRunId.should.be.a('string');
done();
} else {
done(error || response.statusCode);
}
});
});
it('should respond run status: running', function(done) {
this.timeout(5000);
request({
method: 'GET',
url: serverUrl + '/api/runs/' + asyncRunId,
json: true,
headers: {
'X-Api-Key': Object.keys(config.authorizedKeys)[0]
}
}, function(error, response, body) {
if (!error && response.statusCode === 200) {
body.runId.should.equal(asyncRunId);
body.status.should.deep.equal({
statusCode: 'running'
});
done();
} else {
@@ -79,13 +166,16 @@ describe('api', function() {
request({
method: 'POST',
url: apiUrl + '/runs',
url: serverUrl + '/api/runs',
body: {
url: wwwUrl + '/simple-page.html',
waitForResponse: false
},
json: true
}, function(error, response, body) {
lastRunId = body.runId;
if (error) {
deferred.reject(error);
} else {
@@ -131,6 +221,110 @@ describe('api', function() {
});
it('should respond 404 to unknown runId', function(done) {
this.timeout(5000);
request({
method: 'GET',
url: serverUrl + '/api/runs/unknown',
json: true
}, function(error, response, body) {
if (!error && response.statusCode === 404) {
done();
} else {
done(error || response.statusCode);
}
});
});
it('should respond 404 to unknown result', function(done) {
this.timeout(5000);
request({
method: 'GET',
url: serverUrl + '/api/results/unknown',
json: true
}, function(error, response, body) {
if (!error && response.statusCode === 404) {
done();
} else {
done(error || response.statusCode);
}
});
});
it('should respond status complete to the first run', function(done) {
this.timeout(12000);
function checkStatus() {
request({
method: 'GET',
url: serverUrl + '/api/runs/' + asyncRunId,
json: true
}, function(error, response, body) {
if (!error && response.statusCode === 200) {
body.runId.should.equal(asyncRunId);
if (body.status.statusCode === 'running') {
setTimeout(checkStatus, 250);
} else if (body.status.statusCode === 'complete') {
done();
} else {
done(body.status.statusCode);
}
} else {
done(error || response.statusCode);
}
});
}
checkStatus();
});
it('should find the result of the async run', function(done) {
this.timeout(5000);
request({
method: 'GET',
url: serverUrl + '/api/results/' + asyncRunId,
json: true,
}, function(error, response, body) {
if (!error && response.statusCode === 200) {
body.should.have.a.property('runId').that.equals(asyncRunId);
body.should.have.a.property('params').that.is.an('object');
body.params.url.should.equal(wwwUrl + '/simple-page.html');
body.should.have.a.property('scoreProfiles').that.is.an('object');
body.scoreProfiles.should.have.a.property('generic').that.is.an('object');
body.scoreProfiles.generic.should.have.a.property('globalScore').that.is.a('number');
body.scoreProfiles.generic.should.have.a.property('categories').that.is.an('object');
body.should.have.a.property('rules').that.is.an('object');
body.should.have.a.property('toolsResults').that.is.an('object');
body.toolsResults.should.have.a.property('phantomas').that.is.an('object');
body.should.have.a.property('javascriptExecutionTree').that.is.an('object');
body.javascriptExecutionTree.should.have.a.property('data').that.is.an('object');
body.javascriptExecutionTree.data.should.have.a.property('type').that.equals('main');
done();
} else {
done(error || response.statusCode);
}
});
});
// Stop the server
after(function() {
console.log('Closing the server');
apiServer.close();
+18
View File
@@ -0,0 +1,18 @@
var should = require('chai').should();
var scoreCalculator = require('../../lib/scoreCalculator');
describe('scoreCalculator', function() {
it('should have a method calculate', function() {
scoreCalculator.should.have.property('calculate').that.is.a('function');
});
it('should produce a nice rules object', function() {
var data = require('../fixtures/scoreInput.json');
var profile = require('../fixtures/scoreProfile.json');
var expected = require('../fixtures/scoreOutput.json');
var results = scoreCalculator.calculate(data, profile);
results.should.deep.equals(expected);
});
});
+11 -4
View File
@@ -9,28 +9,28 @@ chai.use(sinonChai);
describe('yellowlabtools', function() {
it('returns a promise', function() {
it('should return a promise', function() {
var ylt = new YellowLabTools();
ylt.should.have.property('then').that.is.a('function');
ylt.should.have.property('fail').that.is.a('function');
});
it('fails an undefined url', function(done) {
it('should fail an undefined url', function(done) {
var ylt = new YellowLabTools().fail(function(err) {
err.should.be.a('string').that.equals('URL missing');
done();
});
});
it('fails with an empty url string', function(done) {
it('should fail with an empty url string', function(done) {
var ylt = new YellowLabTools('').fail(function(err) {
err.should.be.a('string').that.equals('URL missing');
done();
});
});
it('succeeds on simple-page.html', function(done) {
it('should succeeds on simple-page.html', function(done) {
this.timeout(15000);
// Check if console.log is called
@@ -75,6 +75,13 @@ describe('yellowlabtools', function() {
"offenders": ["body > h1[1]"]
});
// Test javascriptExecutionTree
data.toolsResults.phantomas.metrics.should.not.have.a.property('javascriptExecutionTree');
data.toolsResults.phantomas.offenders.should.not.have.a.property('javascriptExecutionTree');
data.should.have.a.property('javascriptExecutionTree').that.is.an('object');
data.javascriptExecutionTree.should.have.a.property('data');
data.javascriptExecutionTree.data.should.have.a.property('type').that.equals('main');
/*jshint expr: true*/
console.log.should.not.have.been.called;
+68
View File
@@ -0,0 +1,68 @@
{
"rules": {
"metric1": {
"policy": {
"tool": "tool1",
"label": "The metric 1",
"message": "A great message",
"isOkThreshold": 1000,
"isBadThreshold": 3000,
"isAbnormalThreshold": 5000
},
"value": 1236,
"bad": true,
"abnormal": false,
"score": 88,
"abnormalityScore": 0
},
"metric2": {
"value": 222,
"bad": false,
"abnormal": false,
"score": 100,
"abnormalityScore": 0
},
"metric3": {
"value": 6666,
"bad": true,
"abnormal": true,
"score": 0,
"abnormalityScore": -42
},
"metric4": {
"value": 1000,
"bad": false,
"abnormal": false,
"score": 100,
"abnormalityScore": 0
},
"metric5": {
"value": 3000,
"bad": true,
"abnormal": false,
"score": 0,
"abnormalityScore": 0
},
"metric6": {
"value": 0,
"bad": false,
"abnormal": false,
"score": 100,
"abnormalityScore": 0
},
"metric7": {
"value": 5000,
"bad": true,
"abnormal": true,
"score": 0,
"abnormalityScore": 0
},
"metric8": {
"value": 22,
"bad": true,
"abnormal": true,
"score": 0,
"abnormalityScore": -100
}
}
}
+34
View File
@@ -0,0 +1,34 @@
{
"globalScore": 69,
"categories": {
"category1": {
"label": "Category 1",
"categoryScore": 87,
"rules": [
"metric1",
"metric2",
"metric3",
"metric4"
]
},
"category2": {
"label": "Category 2",
"categoryScore": 31,
"rules": [
"metric5",
"metric6",
"metric7",
"metric8",
"unexistantMetric1"
]
},
"category3": {
"label": "Category 3",
"categoryScore": 100,
"rules": [
"unexistantMetric1",
"unexistantMetric2"
]
}
}
}
+35
View File
@@ -0,0 +1,35 @@
{
"categories": {
"category1": {
"label": "Category 1",
"policies": {
"metric1": 2,
"metric2": 1,
"metric3": 0.5,
"metric4": 2
}
},
"category2": {
"label": "Category 2",
"policies": {
"metric5": 2,
"metric6": 1,
"metric7": 0.5,
"metric8": 2,
"unexistantMetric1": 1
}
},
"category3": {
"label": "Category 3",
"policies": {
"unexistantMetric1": 2,
"unexistantMetric2": 1
}
}
},
"globalScore": {
"category1": 2,
"category2": 1,
"category3": 0.1
}
}