Writing the API (workin in progress)
This commit is contained in:
+4
-3
@@ -36,7 +36,8 @@ module.exports = function(grunt) {
|
||||
'lib/**/*.js',
|
||||
'app/nodeControllers/*.js',
|
||||
'app/public/scripts/*.js',
|
||||
'phantomas_custom/**/*.js'
|
||||
'phantomas_custom/**/*.js',
|
||||
'test/**/*.js'
|
||||
]
|
||||
},
|
||||
clean: {
|
||||
@@ -70,13 +71,13 @@ module.exports = function(grunt) {
|
||||
options: {
|
||||
reporter: 'spec',
|
||||
},
|
||||
src: ['coverage/test/api/*.js']
|
||||
src: ['coverage/test/api/*.js', 'coverage/test/server/*.js']
|
||||
},
|
||||
'test-current-work': {
|
||||
options: {
|
||||
reporter: 'spec',
|
||||
},
|
||||
src: ['coverage/test/api/yellowlabtoolsTest.js']
|
||||
src: ['coverage/test/server/runsQueueTest.js']
|
||||
},
|
||||
coverage: {
|
||||
options: {
|
||||
|
||||
@@ -1,66 +0,0 @@
|
||||
/**
|
||||
* Creation of a queue and it's worker function
|
||||
*/
|
||||
|
||||
var util = require('util');
|
||||
var EventEmitter = require('events').EventEmitter;
|
||||
var async = require('async');
|
||||
var phantomasWrapper = require('./phantomasWrapper');
|
||||
|
||||
|
||||
var testQueue = function() {
|
||||
'use strict';
|
||||
|
||||
var currentTask = null;
|
||||
var self = this;
|
||||
|
||||
var queue = async.queue(function(task, callback) {
|
||||
currentTask = task;
|
||||
|
||||
console.log('Starting test ' + task.testId);
|
||||
|
||||
phantomasWrapper.execute(task, function(err, json, results) {
|
||||
console.log('Test ' + task.testId + ' complete');
|
||||
currentTask = null;
|
||||
callback(err, json, results);
|
||||
self.emit('queueMoving');
|
||||
});
|
||||
});
|
||||
|
||||
|
||||
// Use this method to add a test to the queue
|
||||
this.push = queue.push;
|
||||
|
||||
|
||||
// Gives the position of a task in the queue
|
||||
// Returns 0 if it is the current running task
|
||||
// Returns -1 if not found
|
||||
this.indexOf = function(testId) {
|
||||
if (currentTask && currentTask.testId === testId) {
|
||||
return 0;
|
||||
}
|
||||
|
||||
var position = -1;
|
||||
if (queue.length() > 0) {
|
||||
queue.tasks.forEach(function(task, index) {
|
||||
if (task.data.testId === testId) {
|
||||
position = index + 1;
|
||||
}
|
||||
});
|
||||
}
|
||||
return position;
|
||||
};
|
||||
|
||||
this.testComplete = function(testId) {
|
||||
self.emit('testComplete', testId);
|
||||
};
|
||||
|
||||
this.testFailed = function(testId) {
|
||||
self.emit('testFailed', testId);
|
||||
};
|
||||
};
|
||||
|
||||
// extend the EventEmitter class
|
||||
util.inherits(testQueue, EventEmitter);
|
||||
|
||||
module.exports = new testQueue();
|
||||
@@ -0,0 +1,22 @@
|
||||
// Config file
|
||||
var settings = require('../server_config/settings.json');
|
||||
|
||||
var express = require('express');
|
||||
var app = express();
|
||||
var server = require('http').createServer(app);
|
||||
var bodyParser = require('body-parser');
|
||||
var compress = require('compression');
|
||||
|
||||
app.use(compress());
|
||||
app.use(bodyParser.urlencoded({ extended: false }));
|
||||
|
||||
|
||||
// Initialize the controllers
|
||||
var apiController = require('../lib/server/controllers/apiController')(app);
|
||||
var uiController = require('../lib/server/controllers/uiController')(app);
|
||||
|
||||
|
||||
// Launch the server
|
||||
server.listen(settings.serverPort, function() {
|
||||
console.log('Listening on port %d', server.address().port);
|
||||
});
|
||||
@@ -0,0 +1,86 @@
|
||||
var debug = require('debug')('ylt:server');
|
||||
|
||||
var runsQueue = require('../datastores/runsQueue');
|
||||
var runsDatastore = require('../datastores/runsDatastore');
|
||||
|
||||
|
||||
function ApiController(app) {
|
||||
'use strict';
|
||||
|
||||
// Retrieve the list of all runs
|
||||
/*app.get('/runs', function(req, res) {
|
||||
// NOT YET
|
||||
});*/
|
||||
|
||||
// Create a new run
|
||||
app.post('/runs', function(req, res) {
|
||||
|
||||
// Grab the test parameters
|
||||
var run = {
|
||||
// Generate a random run ID
|
||||
_id: (Date.now()*1000 + Math.round(Math.random()*1000)).toString(36),
|
||||
params: {
|
||||
url: req.body.url,
|
||||
waitForResponse: req.body.waitForResponse || true
|
||||
}
|
||||
};
|
||||
|
||||
// Add test to the testQueue
|
||||
debug('Adding test %s to the queue', run._id);
|
||||
var queuing = runsQueue.push(run._id);
|
||||
|
||||
|
||||
// Save the run to the datastore
|
||||
var position = runsQueue.getPosition(run._id);
|
||||
run.status = {
|
||||
statusCode: (position === 0) ? STATUS_RUNNING : STATUS_AWAITING,
|
||||
position: position
|
||||
};
|
||||
runsDatastore.add(run);
|
||||
|
||||
|
||||
// Listening for position updates
|
||||
queuing.progress(function(position) {
|
||||
var savedRun = runsDatastore.get(run._id);
|
||||
savedRun.status = {
|
||||
statusCode: STATUS_AWAITING,
|
||||
position: position
|
||||
};
|
||||
runsDatastore.update(savedRun);
|
||||
});
|
||||
|
||||
|
||||
queuing.then(function() {
|
||||
|
||||
});
|
||||
|
||||
// The user doesn't not want to wait for the response
|
||||
if (!params.waitForResponse) {
|
||||
|
||||
// Sending just the test id
|
||||
res.setHeader('Content-Type', 'application/javascript');
|
||||
res.send(JSON.stringify({
|
||||
testId: testId
|
||||
}));
|
||||
}
|
||||
});
|
||||
|
||||
// Retrive one run by id
|
||||
app.get('/run/:id', function(req, res) {
|
||||
|
||||
});
|
||||
|
||||
// Delete one run by id
|
||||
/*app.delete('/run/:id', function(req, res) {
|
||||
// NOT YET
|
||||
});*/
|
||||
|
||||
|
||||
var STATUS_AWAITING = 'awaiting';
|
||||
var STATUS_RUNNING = 'running';
|
||||
var STATUS_DONE = 'done';
|
||||
var STATUS_FAILED = 'failed';
|
||||
|
||||
}
|
||||
|
||||
module.exports = ApiController;
|
||||
@@ -0,0 +1,9 @@
|
||||
|
||||
|
||||
function ResultsDatastore() {
|
||||
'use strict';
|
||||
|
||||
|
||||
}
|
||||
|
||||
module.exports = ResultsDatastore;
|
||||
@@ -0,0 +1,36 @@
|
||||
|
||||
|
||||
function RunsDatastore() {
|
||||
'use strict';
|
||||
|
||||
// NOT PERSISTING RUNS
|
||||
// For the moment, maybe one day
|
||||
var runs = {};
|
||||
|
||||
|
||||
this.add = function(run) {
|
||||
runs[run._id] = run;
|
||||
};
|
||||
|
||||
this.get = function(runId) {
|
||||
return runs[runId];
|
||||
};
|
||||
|
||||
this.update = function(run) {
|
||||
runs[run._id] = run;
|
||||
};
|
||||
|
||||
this.delete = function(runId) {
|
||||
delete runs[runId];
|
||||
};
|
||||
|
||||
this.list = function() {
|
||||
var runsArray = [];
|
||||
Object.keys(runs).forEach(function(key) {
|
||||
runsArray.push(runs[key]);
|
||||
});
|
||||
return runsArray;
|
||||
};
|
||||
}
|
||||
|
||||
module.exports = RunsDatastore;
|
||||
@@ -0,0 +1,73 @@
|
||||
var Q = require('q');
|
||||
|
||||
|
||||
function RunsQueue() {
|
||||
'use strict';
|
||||
|
||||
var queue = [];
|
||||
|
||||
|
||||
this.push = function(runId) {
|
||||
var deferred = Q.defer();
|
||||
|
||||
if (queue.length === 0) {
|
||||
|
||||
// The queue is empty, let's run immediatly
|
||||
queue.push({
|
||||
runId: runId
|
||||
});
|
||||
|
||||
deferred.resolve();
|
||||
|
||||
} else {
|
||||
|
||||
queue.push({
|
||||
runId: runId,
|
||||
positionChangedCallback: function(position) {
|
||||
deferred.notify(position);
|
||||
},
|
||||
itIsTimeCallback: function() {
|
||||
deferred.resolve();
|
||||
}
|
||||
});
|
||||
}
|
||||
|
||||
return deferred.promise;
|
||||
};
|
||||
|
||||
|
||||
this.getPosition = function(runId) {
|
||||
// Position 0 means it's a work in progress (a run is removed AFTER it is finished, not before)
|
||||
var position = -1;
|
||||
|
||||
queue.some(function(run, index) {
|
||||
if (run.runId === runId) {
|
||||
position = index;
|
||||
return true;
|
||||
}
|
||||
return false;
|
||||
});
|
||||
|
||||
return position;
|
||||
};
|
||||
|
||||
|
||||
this.remove = function(runId) {
|
||||
var position = this.getPosition(runId);
|
||||
if (position >= 0) {
|
||||
queue.splice(position, 1);
|
||||
}
|
||||
|
||||
// Update other runs' positions
|
||||
queue.forEach(function(run, index) {
|
||||
if (index === 0 && run.itIsTimeCallback) {
|
||||
run.itIsTimeCallback();
|
||||
} else if (index > 0 && run.positionChangedCallback) {
|
||||
run.positionChangedCallback(index);
|
||||
}
|
||||
});
|
||||
|
||||
};
|
||||
}
|
||||
|
||||
module.exports = RunsQueue;
|
||||
+1
-1
@@ -14,7 +14,7 @@
|
||||
"body-parser": "~1.9.2",
|
||||
"compression": "~1.2.0",
|
||||
"debug": "^2.1.0",
|
||||
"express": "~4.10.1",
|
||||
"express": "~4.10.4",
|
||||
"phantomas": "1.7.0",
|
||||
"socket.io": "~1.2.0"
|
||||
},
|
||||
|
||||
@@ -23,9 +23,9 @@ describe('phantomasWrapper', function() {
|
||||
data.should.have.a.property('generator');
|
||||
data.generator.should.contain('phantomas');
|
||||
data.should.have.a.property('url').that.equals(url);
|
||||
data.should.have.a.property('metrics').that.is.an('object').not.empty;
|
||||
data.should.have.a.property('offenders').that.is.an('object').not.empty;
|
||||
data.offenders.should.have.a.property('javascriptExecutionTree').that.is.a('array').not.empty;
|
||||
data.should.have.a.property('metrics').that.is.an('object').not.empty();
|
||||
data.should.have.a.property('offenders').that.is.an('object').not.empty();
|
||||
data.offenders.should.have.a.property('javascriptExecutionTree').that.is.a('array').not.empty();
|
||||
|
||||
done();
|
||||
}).fail(function(err) {
|
||||
@@ -73,9 +73,9 @@ describe('phantomasWrapper', function() {
|
||||
data.should.have.a.property('generator');
|
||||
data.generator.should.contain('phantomas');
|
||||
data.should.have.a.property('url').that.equals(url);
|
||||
data.should.have.a.property('metrics').that.is.an('object').not.empty;
|
||||
data.should.have.a.property('offenders').that.is.an('object').not.empty;
|
||||
data.offenders.should.have.a.property('javascriptExecutionTree').that.is.a('array').not.empty;
|
||||
data.should.have.a.property('metrics').that.is.an('object').not.empty();
|
||||
data.should.have.a.property('offenders').that.is.an('object').not.empty();
|
||||
data.offenders.should.have.a.property('javascriptExecutionTree').that.is.a('array').not.empty();
|
||||
|
||||
done();
|
||||
}).fail(function(err) {
|
||||
|
||||
@@ -34,7 +34,7 @@ describe('yellowlabtools', function() {
|
||||
this.timeout(15000);
|
||||
|
||||
// Check if console.log is called
|
||||
sinon.spy(console, 'log')
|
||||
sinon.spy(console, 'log');
|
||||
|
||||
var url = 'http://localhost:8388/simple-page.html';
|
||||
|
||||
@@ -75,6 +75,7 @@ describe('yellowlabtools', function() {
|
||||
"offenders": ["body > h1[1]"]
|
||||
});
|
||||
|
||||
/*jshint expr: true*/
|
||||
console.log.should.not.have.been.called;
|
||||
|
||||
done();
|
||||
|
||||
@@ -0,0 +1,41 @@
|
||||
var should = require('chai').should();
|
||||
var runsDatastore = require('../../lib/server/datastores/runsDatastore');
|
||||
|
||||
describe('runsDatastore', function() {
|
||||
|
||||
var datastore = new runsDatastore();
|
||||
|
||||
var randomId = Math.round(Math.random() * 100000);
|
||||
|
||||
it('should accept a new run', function() {
|
||||
datastore.should.have.a.property('add').that.is.a('function');
|
||||
|
||||
datastore.add({
|
||||
_id: randomId,
|
||||
otherData: 123456789
|
||||
});
|
||||
});
|
||||
|
||||
it('should have stored the run', function() {
|
||||
datastore.should.have.a.property('get').that.is.a('function');
|
||||
|
||||
var run = datastore.get(randomId);
|
||||
|
||||
run.should.have.a.property('_id').that.equals(randomId);
|
||||
});
|
||||
|
||||
it('should have exactly 1 run in the store', function() {
|
||||
var runs = datastore.list();
|
||||
runs.should.be.a('array');
|
||||
runs.should.have.length(1);
|
||||
runs[0].should.have.a.property('_id').that.equals(randomId);
|
||||
});
|
||||
|
||||
it('should delete the run', function() {
|
||||
datastore.delete(randomId);
|
||||
|
||||
var runs = datastore.list();
|
||||
runs.should.be.a('array');
|
||||
runs.should.have.length(0);
|
||||
});
|
||||
});
|
||||
@@ -0,0 +1,64 @@
|
||||
var should = require('chai').should();
|
||||
var runsQueue = require('../../lib/server/datastores/runsQueue.js');
|
||||
|
||||
describe('runsQueue', function() {
|
||||
|
||||
var queue = new runsQueue();
|
||||
var cccRun = null;
|
||||
|
||||
it('should accept a new runId', function(done) {
|
||||
queue.should.have.a.property('push').that.is.a('function');
|
||||
|
||||
var aaaRun = queue.push('aaa');
|
||||
queue.push('bbb');
|
||||
|
||||
aaaRun.then(function() {
|
||||
done();
|
||||
});
|
||||
});
|
||||
|
||||
it('should return the right positions', function() {
|
||||
var aaaPosition = queue.getPosition('aaa');
|
||||
aaaPosition.should.equal(0);
|
||||
|
||||
var bbbPosition = queue.getPosition('bbb');
|
||||
bbbPosition.should.equal(1);
|
||||
|
||||
var cccPosition = queue.getPosition('ccc');
|
||||
cccPosition.should.equal(-1);
|
||||
});
|
||||
|
||||
it('should refresh runs\' positions', function(done) {
|
||||
cccRun = queue.push('ccc');
|
||||
|
||||
cccRun.progress(function(position) {
|
||||
position.should.equal(1);
|
||||
|
||||
var positionDoubleCheck = queue.getPosition('ccc');
|
||||
positionDoubleCheck.should.equal(1);
|
||||
|
||||
done();
|
||||
});
|
||||
|
||||
queue.remove('aaa');
|
||||
});
|
||||
|
||||
it('should fulfill the promise when first in the line', function(done) {
|
||||
cccRun.then(function() {
|
||||
done();
|
||||
});
|
||||
|
||||
queue.remove('bbb');
|
||||
});
|
||||
|
||||
it('should not keep removed runs', function() {
|
||||
var aaaPosition = queue.getPosition('aaa');
|
||||
aaaPosition.should.equal(-1);
|
||||
|
||||
var bbbPosition = queue.getPosition('bbb');
|
||||
bbbPosition.should.equal(-1);
|
||||
|
||||
var cccPosition = queue.getPosition('ccc');
|
||||
cccPosition.should.equal(0);
|
||||
});
|
||||
});
|
||||
@@ -1,23 +0,0 @@
|
||||
var should = require('chai').should();
|
||||
var testQueue = require('../../app/lib/testQueue.js');
|
||||
|
||||
describe('testQueue', function() {
|
||||
|
||||
var url = 'http://www.not.existing';
|
||||
|
||||
it('should accept a new test with method push', function() {
|
||||
testQueue.should.have.property('push').that.is.a('function');
|
||||
|
||||
var task = {
|
||||
testId: 'aaaaa',
|
||||
url: url,
|
||||
options: {}
|
||||
};
|
||||
|
||||
testQueue.push(task, function(err, json, results) {
|
||||
done();
|
||||
});
|
||||
|
||||
});
|
||||
|
||||
});
|
||||
Reference in New Issue
Block a user