From 6273ad65238e557c978fefa601393afca4f9fbfb Mon Sep 17 00:00:00 2001 From: petea Date: Sat, 6 Sep 2014 20:30:14 +0200 Subject: [PATCH 01/10] petea - updated test/processingChain.js test for findFirstValidItem --- test/processingChain.js | 1 + 1 file changed, 1 insertion(+) diff --git a/test/processingChain.js b/test/processingChain.js index fb96807..a0d279b 100644 --- a/test/processingChain.js +++ b/test/processingChain.js @@ -54,6 +54,7 @@ describe('Processing Chain methods', function() { pc = new ProcessingChain() pc.add({fn: 1, names: ['first']}) pc.add({fn: 2, names: ['second']}) + pc.findFirstValidItem('first').fn.should.equal(1) pc.findFirstValidItem('second').fn.should.equal(2) }) }) From 826eef2aeaeada48711a25e175f03686ca431dd8 Mon Sep 17 00:00:00 2001 From: petea Date: Sat, 6 Sep 2014 21:26:39 +0200 Subject: [PATCH 02/10] petea - added one more test for processingChain.runChain which consider use of handler name --- lib/processingChain.js | 13 ++++++++---- test/processingChain.js | 47 +++++++++++++++++++++++++++++++++++++---- 2 files changed, 52 insertions(+), 8 deletions(-) diff --git a/lib/processingChain.js b/lib/processingChain.js index f5bff87..c37cd1c 100644 --- a/lib/processingChain.js +++ b/lib/processingChain.js @@ -49,11 +49,16 @@ ProcessingChain.prototype.runChain = function( req, res, finalFn, handler ) { totalItems = self.errorHandlers.length; } if ( currentItem < totalItems - 1 ) { - for(var idx = currentItem + 1; idx < chain.length; idx++) { - if( (chain[idx].names && chain[idx].names.indexOf(handler.name) != -1) || !chain[idx].names) { - break + var idx = ++currentItem; + + if( handler && handler.name) { + for(; idx < chain.length; idx++) { + if( (chain[idx].names && chain[idx].names.indexOf(handler.name) != -1) || !chain[idx].names) { + break + } } - } + } + currentItem = idx if(err) { chain[currentItem].fn(err, req, res, nextError) diff --git a/test/processingChain.js b/test/processingChain.js index a0d279b..e54cd54 100644 --- a/test/processingChain.js +++ b/test/processingChain.js @@ -60,7 +60,7 @@ describe('Processing Chain methods', function() { }) describe("@runChain", function() { - it("should run the chain correctly", function(done) { + it("should run the chain correctly without handler name", function(done) { var result = "" pc = new ProcessingChain() pc.add({fn: function(req, res, n) { @@ -68,9 +68,11 @@ describe('Processing Chain methods', function() { n() }}) pc.add({fn: function(req, res, n) { - result+= "2" - n() - }}) + result+= "2" + n() + }, + names: ['ok'], + }) pc.add({fn: function(req, res, n) { result+= "3" n() @@ -81,6 +83,43 @@ describe('Processing Chain methods', function() { }, null) }) + it("should run the chain correctly with handler name", function(done) { + var result = "" + pc = new ProcessingChain() + pc.add({fn: function(req, res, n) { + result+= "1" + n() + }}) + pc.add({fn: function(req, res, n) { + result+= "2" + n() + }, + names: ['ok'], + }) + pc.add({fn: function(req, res, n) { + result+= "3" + n() + }}) + + pc.add({fn: function(req, res, n) { + result+= "4" + n() + }, + names: ['not ok', 'nott1 ok'] + }); + + pc.add({fn: function(req, res, n) { + result+= "5" + n() + }, + names: ['not ok', 'ok'] + }); + pc.runChain({}, {}, function() { + result.should.equal("1235") + done() + }, {name: 'ok'}) + }) + it("should switch to the error chain if there is a problem", function(done) { var result = "" pc = new ProcessingChain() From 5c255fe6316f6db1df7f324e33f1c514ad75e6d7 Mon Sep 17 00:00:00 2001 From: petea Date: Sun, 7 Sep 2014 08:37:48 +0200 Subject: [PATCH 03/10] petea - modified processingChain.add method --- lib/processingChain.js | 3 +++ lib/vatican.js | 4 ++-- 2 files changed, 5 insertions(+), 2 deletions(-) diff --git a/lib/processingChain.js b/lib/processingChain.js index c37cd1c..348e830 100644 --- a/lib/processingChain.js +++ b/lib/processingChain.js @@ -9,6 +9,9 @@ function ProcessingChain( ) { } ProcessingChain.prototype.add = function( proc ) { + proc.names = proc.names ? + ( Array.isArray(proc.names) ? proc.names : Array(proc.names) ) + : []; if(proc.fn.length == 4) //it's an error handler this.errorHandlers.push(proc); else diff --git a/lib/vatican.js b/lib/vatican.js index eaa6a3a..b9f5e97 100644 --- a/lib/vatican.js +++ b/lib/vatican.js @@ -43,12 +43,12 @@ function Vatican(options) { } Vatican.prototype.preprocess = function(fn, endpointNames) { - this.preprocessors.add({fn: fn, names: endpointNames ? endpointNames : []}) + this.preprocessors.add({fn: fn, names: endpointNames}) this.totalPreprocessors = this.preprocessors.getTotal(); } Vatican.prototype.postprocess = function(fn, endpointNames) { - this.postprocessors.add({fn: fn, names: endpointNames ? endpointNames : []}); + this.postprocessors.add({fn: fn, names: endpointNames}); } Vatican.prototype.parseHandlers = function(cb) { From 3e7486fc2a89e5e15b43c3c3ce3b83b4e52c79f4 Mon Sep 17 00:00:00 2001 From: petea Date: Sun, 14 Sep 2014 09:05:50 +0200 Subject: [PATCH 04/10] petea - changed signiture for processingChain.runChain function + adjust the tests --- lib/processingChain.js | 11 +++++++-- lib/vatican.js | 9 ++++++-- lib/vaticanResponse.js | 40 ++++++++++++++++++--------------- test/processingChain.js | 50 ++++++++++++++++++++++++++++------------- 4 files changed, 72 insertions(+), 38 deletions(-) diff --git a/lib/processingChain.js b/lib/processingChain.js index 348e830..ce47bbd 100644 --- a/lib/processingChain.js +++ b/lib/processingChain.js @@ -26,7 +26,14 @@ ProcessingChain.prototype.pop = function() { this.chain.pop(); } -ProcessingChain.prototype.runChain = function( req, res, finalFn, handler ) { +ProcessingChain.prototype.runChain = function( params ) { + params = params || {}; + console.log('params: ', params); + req = params.req; + res = params.res; + finalFn = params.finalFn; + handler = params.handler; + var currentItem = 0; var totalItems = this.chain.length; var self = this; @@ -56,7 +63,7 @@ ProcessingChain.prototype.runChain = function( req, res, finalFn, handler ) { if( handler && handler.name) { for(; idx < chain.length; idx++) { - if( (chain[idx].names && chain[idx].names.indexOf(handler.name) != -1) || !chain[idx].names) { + if( !chain[idx].names || ( ! chain[idx].names.length ) || ~chain[idx].names.indexOf(handler.name)) { break } } diff --git a/lib/vatican.js b/lib/vatican.js index b9f5e97..245bd72 100644 --- a/lib/vatican.js +++ b/lib/vatican.js @@ -157,9 +157,14 @@ Vatican.prototype.requestHandler = function (req, res) { self.preprocessors.pop(); } var hdlrInstance = new hdlr(self.getCorrectModel(methodFound)) + hdlrInstance.models = self.dbmodels //Let the handler access all other models in case they're neeeded self.preprocessors.add({fn: hdlrInstance[methodFound.action].bind(hdlrInstance)}) - self.preprocessors.runChain(newRequest, res, null, methodFound); + self.preprocessors.runChain({ + req: newRequest, + res: res, + handler: methodFound, + }); }); } catch (ex) { logger.error("Error instantiating handler: " + ex.message); @@ -171,7 +176,7 @@ Vatican.prototype.requestHandler = function (req, res) { Vatican.prototype.getCorrectModel = function(handler) { var modelName = handler.handlerName.replace("Hdlr", '') - return this.dbmodels[modelName] + return this.dbmodels && this.dbmodels[modelName] } /** diff --git a/lib/vaticanResponse.js b/lib/vaticanResponse.js index 472d5fa..77291eb 100644 --- a/lib/vaticanResponse.js +++ b/lib/vaticanResponse.js @@ -17,26 +17,30 @@ VaticanResponse.prototype.send = function(txt) { var headers = {}; var self = this; this.body = txt; - this.ppChain.runChain(this.request, this, function(req, resp) { - //Check for CORS config - if(self.options.cors !== false) { - headers = _getCORSHeaders(self.options.cors); - } + this.ppChain.runChain({ + req: this.request, + res: this, + finalFn: function(req, resp) { + //Check for CORS config + if(self.options.cors !== false) { + headers = _getCORSHeaders(self.options.cors); + } - //Adds the rest of the headers - for(var i in resp.headers) { - headers = _.assign(headers, resp.headers[i]); - } + //Adds the rest of the headers + for(var i in resp.headers) { + headers = _.assign(headers, resp.headers[i]); + } - //Write the headers - resp.response.writeHead(resp.statusCode, headers); - if( typeof resp.body == 'object') { - resp.body = JSON.stringify(resp.body); - } + //Write the headers + resp.response.writeHead(resp.statusCode, headers); + if( typeof resp.body == 'object') { + resp.body = JSON.stringify(resp.body); + } - //Write out the response text - resp.response.write(resp.body); - resp.response.end(); + //Write out the response text + resp.response.write(resp.body); + resp.response.end(); + }, }) }; @@ -95,4 +99,4 @@ function _getCORSHeaders(corsOpts) { module.exports = { improveResponse: _improveResponse, writeNotFound: _writeNotFound -}; \ No newline at end of file +}; diff --git a/test/processingChain.js b/test/processingChain.js index e54cd54..9a15dac 100644 --- a/test/processingChain.js +++ b/test/processingChain.js @@ -77,10 +77,14 @@ describe('Processing Chain methods', function() { result+= "3" n() }}) - pc.runChain({}, {}, function() { - result.should.equal("123") - done() - }, null) + pc.runChain({ + req: {}, + res: {}, + finalFn: function() { + result.should.equal("123") + done() + }, + }) }) it("should run the chain correctly with handler name", function(done) { @@ -114,10 +118,15 @@ describe('Processing Chain methods', function() { }, names: ['not ok', 'ok'] }); - pc.runChain({}, {}, function() { - result.should.equal("1235") - done() - }, {name: 'ok'}) + pc.runChain({ + req: {}, + res: {}, + finalFn: function() { + result.should.equal("1235") + done() + }, + handler: {name: 'ok'} + }) }) it("should switch to the error chain if there is a problem", function(done) { @@ -144,10 +153,14 @@ describe('Processing Chain methods', function() { result += 'e2' n() }}) - pc.runChain({}, {}, function() { - result.should.equal("12errore2") - done() - }, null) + pc.runChain({ + req: {}, + res: {}, + finalFn: function() { + result.should.equal("12errore2") + done() + } + }) }) it("should run correctly if there are named endpoints involved", function(done) { @@ -171,10 +184,15 @@ describe('Processing Chain methods', function() { n() }, names: ["endpoint2", "endpoint1"]}) - pc.runChain({}, {}, function() { - result.should.equal("134") - done() - }, {name: 'endpoint2'}) + pc.runChain({ + req: {}, + res: {}, + finalFn: function() { + result.should.equal("134") + done() + }, + handler: {name: 'endpoint2'} + }) }) }) }) From ec08aca1f534b0adf9e7d2604911a85e8f25c0d9 Mon Sep 17 00:00:00 2001 From: petea Date: Sun, 14 Sep 2014 09:42:44 +0200 Subject: [PATCH 05/10] petea - issue #20 --- lib/processingChain.js | 25 +++++++++++++------------ lib/vatican.js | 9 ++------- test/processingChain.js | 6 +++--- 3 files changed, 18 insertions(+), 22 deletions(-) diff --git a/lib/processingChain.js b/lib/processingChain.js index ce47bbd..51831b3 100644 --- a/lib/processingChain.js +++ b/lib/processingChain.js @@ -28,14 +28,15 @@ ProcessingChain.prototype.pop = function() { ProcessingChain.prototype.runChain = function( params ) { params = params || {}; - console.log('params: ', params); - req = params.req; - res = params.res; - finalFn = params.finalFn; - handler = params.handler; + var req = params.req; + var res = params.res; + var finalFn = params.finalFn; + var handler = params.handler; + var endPrep = params.endPrep || []; //last preprocessor var currentItem = 0; - var totalItems = this.chain.length; + var chain = [].concat(this.chain, endPrep); + var totalItems = chain.length; var self = this; if(totalItems == 0) { if(typeof finalFn == 'function') finalFn(req, res); @@ -52,7 +53,7 @@ ProcessingChain.prototype.runChain = function( params ) { } var next = function(err) { - var chain = self.chain; + //chain is taken from the closure if ( err ) { //If there is an error, switch to the error handlers chain chain = self.errorHandlers; currentItem = -1; @@ -80,16 +81,16 @@ ProcessingChain.prototype.runChain = function( params ) { } } if(handler) { - var firstItem = self.findFirstValidItem(handler.name) + var firstItem = self.findFirstValidItem(handler.name, chain) firstItem.fn(req, res, next) } else { - this.chain[0].fn(req, res, next ) + chain[0].fn(req, res, next ) } }; -ProcessingChain.prototype.findFirstValidItem = function(name) { - if(!name) return this.chain[0] - return _.find(this.chain, function(item) { +ProcessingChain.prototype.findFirstValidItem = function(name, chain) { + if(!name) return chain[0] + return _.find(chain, function(item) { if(item.names && Array.isArray(item.names) && item.names.length > 0) { return item.names.indexOf(name) != -1 } else { diff --git a/lib/vatican.js b/lib/vatican.js index 245bd72..ed5124f 100644 --- a/lib/vatican.js +++ b/lib/vatican.js @@ -37,14 +37,12 @@ function Vatican(options) { this.parseHandlers(); this.paths = []; this.server = null; - this.totalPreprocessors = 0; this.preprocessors = new processingChain(); this.postprocessors = new processingChain(); } Vatican.prototype.preprocess = function(fn, endpointNames) { this.preprocessors.add({fn: fn, names: endpointNames}) - this.totalPreprocessors = this.preprocessors.getTotal(); } Vatican.prototype.postprocess = function(fn, endpointNames) { @@ -152,18 +150,15 @@ Vatican.prototype.requestHandler = function (req, res) { res = vaticanResp.improveResponse(res, request, this.options, this.postprocessors); //Parse the request to grab the parameters this.parseRequest(request, methodFound.url, req, function(newRequest) { - //Run the pre-process chain and finally, call the handler - if(self.preprocessors.getTotal() > self.totalPreprocessors) { - self.preprocessors.pop(); - } var hdlrInstance = new hdlr(self.getCorrectModel(methodFound)) hdlrInstance.models = self.dbmodels //Let the handler access all other models in case they're neeeded - self.preprocessors.add({fn: hdlrInstance[methodFound.action].bind(hdlrInstance)}) + self.preprocessors.runChain({ req: newRequest, res: res, handler: methodFound, + endPrep: hdlrInstance[methodFound.action].bind(hdlrInstance), }); }); } catch (ex) { diff --git a/test/processingChain.js b/test/processingChain.js index 9a15dac..da529c0 100644 --- a/test/processingChain.js +++ b/test/processingChain.js @@ -47,15 +47,15 @@ describe('Processing Chain methods', function() { pc = new ProcessingChain() pc.add({fn: 1}) pc.add({fn: 2}) - pc.findFirstValidItem().fn.should.equal(1) + pc.findFirstValidItem(undefined, pc.chain).fn.should.equal(1) }) it("should correctly find the first valid process when there is an endpoint name set", function() { pc = new ProcessingChain() pc.add({fn: 1, names: ['first']}) pc.add({fn: 2, names: ['second']}) - pc.findFirstValidItem('first').fn.should.equal(1) - pc.findFirstValidItem('second').fn.should.equal(2) + pc.findFirstValidItem('first', pc.chain).fn.should.equal(1) + pc.findFirstValidItem('second', pc.chain).fn.should.equal(2) }) }) From 50f2b4cadc393fa1d289cacc2373d2aa853685f3 Mon Sep 17 00:00:00 2001 From: petea Date: Mon, 15 Sep 2014 20:59:04 +0200 Subject: [PATCH 06/10] petea - fixed bug in runChain function --- lib/processingChain.js | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/lib/processingChain.js b/lib/processingChain.js index 51831b3..5e8a106 100644 --- a/lib/processingChain.js +++ b/lib/processingChain.js @@ -32,7 +32,7 @@ ProcessingChain.prototype.runChain = function( params ) { var res = params.res; var finalFn = params.finalFn; var handler = params.handler; - var endPrep = params.endPrep || []; //last preprocessor + var endPrep = (params.endPrep && {fn: params.endPrep}) || []; //last preprocessor var currentItem = 0; var chain = [].concat(this.chain, endPrep); From 781ade28978d986e051f0c9e6088cd72359fa9c1 Mon Sep 17 00:00:00 2001 From: petea Date: Fri, 19 Sep 2014 21:42:11 +0200 Subject: [PATCH 07/10] petea - added function close vatican server --- lib/vatican.js | 17 +++++++++++++++++ 1 file changed, 17 insertions(+) diff --git a/lib/vatican.js b/lib/vatican.js index ed5124f..b8c3b7f 100644 --- a/lib/vatican.js +++ b/lib/vatican.js @@ -181,6 +181,7 @@ Vatican.prototype.start = function(cb) { try { this.server = http.createServer(this.requestHandler.bind(this)); this.server.listen(this.options.port); + console.log(this.server); logger.info("Server started on port: " + this.options.port); if(typeof cb == 'function') { cb(); @@ -191,6 +192,22 @@ Vatican.prototype.start = function(cb) { } }; +/** + Close the server +*/ +Vatican.prototype.close = function(cb) { + try { + this.server.close(); + logger.info("Server closed"); + if(typeof cb == 'function') { + cb(); + } + } catch (ex) { + logger.error("Error closing server: " + ex.message); + return false; + } +} + Vatican.prototype.dbStart = function(opts, cb) { if(typeof opts === 'function') { cb = opts From a5a0c2cc4393e0bdb2ae225d11ff8c146daf8784 Mon Sep 17 00:00:00 2001 From: petea Date: Sat, 20 Sep 2014 23:36:15 +0200 Subject: [PATCH 08/10] petea - fixed bug with relative/absolute path for handlers from config --- lib/vatican.js | 7 ++++--- 1 file changed, 4 insertions(+), 3 deletions(-) diff --git a/lib/vatican.js b/lib/vatican.js index b8c3b7f..ea459ae 100644 --- a/lib/vatican.js +++ b/lib/vatican.js @@ -5,7 +5,8 @@ var http = require("http"), handlerParser = require("./handlerParser"), processingChain = require("./processingChain"), mongoose = require("mongoose"), - _ = require("lodash"); + _ = require("lodash"), + path = require("path"); module.exports = Vatican; @@ -50,7 +51,7 @@ Vatican.prototype.postprocess = function(fn, endpointNames) { } Vatican.prototype.parseHandlers = function(cb) { - var dir = this.options.handlers; + var dir = path.isAbsolute(this.options.handlers) ? this.options.handlers : process.cwd() + "/" + this.options.handlers; var self = this; handlerParser.parse(dir, function(err, path) { if(typeof cb == 'function' && err) return cb(err) @@ -146,7 +147,7 @@ Vatican.prototype.requestHandler = function (req, res) { } else { try { var request = this.createRequest(req); - var hdlr = this.loadHandler(process.cwd() + "/" + methodFound.handlerPath); + var hdlr = this.loadHandler(methodFound.handlerPath); res = vaticanResp.improveResponse(res, request, this.options, this.postprocessors); //Parse the request to grab the parameters this.parseRequest(request, methodFound.url, req, function(newRequest) { From fc0394f45602ef2165553b58c76fc07713c48e5d Mon Sep 17 00:00:00 2001 From: petea Date: Sun, 21 Sep 2014 22:07:20 +0200 Subject: [PATCH 09/10] petea - tested http methods --- package.json | 1 + .../vaticanHttpMethods/handlers/people.js | 22 +++++++++++++ test/vaticanHttpMethods.js | 32 +++++++++++++++++++ 3 files changed, 55 insertions(+) create mode 100644 test/fixtures/vaticanHttpMethods/handlers/people.js create mode 100644 test/vaticanHttpMethods.js diff --git a/package.json b/package.json index ee8c11f..ed53d47 100644 --- a/package.json +++ b/package.json @@ -24,6 +24,7 @@ "devDependencies": { "should": "4.0.4", "mocha": "1.21.4", + "supertest": "0.13.0", "istanbul": "0.3.0" } } diff --git a/test/fixtures/vaticanHttpMethods/handlers/people.js b/test/fixtures/vaticanHttpMethods/handlers/people.js new file mode 100644 index 0000000..747cfe2 --- /dev/null +++ b/test/fixtures/vaticanHttpMethods/handlers/people.js @@ -0,0 +1,22 @@ +module.exports = People; +var peeps = [ 'user0', 'user1']; +function People() {} +@endpoint (url: /people method: get) +People.prototype.getPeople = function(req, res) { + res.send('get,' + peeps.join(',')); +} + +@endpoint (url: /people method: post) +People.prototype.postPeople = function(req, res) { + res.send('post,' + peeps.join(',')); +} + +@endpoint (url: /people method: put) +People.prototype.putPeople = function(req, res) { + res.send('put,' + peeps.join(',')); +} + +@endpoint (url: /people method: delete) +People.prototype.deletePeople = function(req, res) { + res.send('delete,' + peeps.join(',')); +} diff --git a/test/vaticanHttpMethods.js b/test/vaticanHttpMethods.js new file mode 100644 index 0000000..c2d46c2 --- /dev/null +++ b/test/vaticanHttpMethods.js @@ -0,0 +1,32 @@ +var request = require('supertest'), + should = require('should'), + vatican = require('../'), + http = require('http'); + +describe('vatican http methods', function() { + var app = new vatican({ + 'handlers': __dirname + '/fixtures/vaticanHttpMethods/handlers', + 'port': 24000, + }); + + before(function() { + app.start(); + }); + + after(function() { + app.close(); + }); + + [ + 'get', + 'put', + 'post', + 'delete' + ].forEach(function(method) { + it(method + " method without params", function( done ) { + request('http://localhost:24000')[method]('/people') + .expect(200) //statusCode + .expect(method + ',user0,user1', done); //body + }); + }); +}); From bd2ed55dfcde7e7698ac452104a933d2e3154fe4 Mon Sep 17 00:00:00 2001 From: petea Date: Sun, 21 Sep 2014 23:29:55 +0200 Subject: [PATCH 10/10] petea - added tests for absolute/relative paths from config.handlers --- .../fixtures/vaticanConfig/handlers/people.js | 6 +++ test/vaticanConfig.js | 43 +++++++++++++++++++ 2 files changed, 49 insertions(+) create mode 100644 test/fixtures/vaticanConfig/handlers/people.js create mode 100644 test/vaticanConfig.js diff --git a/test/fixtures/vaticanConfig/handlers/people.js b/test/fixtures/vaticanConfig/handlers/people.js new file mode 100644 index 0000000..9871bcf --- /dev/null +++ b/test/fixtures/vaticanConfig/handlers/people.js @@ -0,0 +1,6 @@ +module.exports = People; +function People() {} +@endpoint (url: /people method: get) +People.prototype.getPeople = function(req, res) { + res.send('ok'); +} diff --git a/test/vaticanConfig.js b/test/vaticanConfig.js new file mode 100644 index 0000000..489ff26 --- /dev/null +++ b/test/vaticanConfig.js @@ -0,0 +1,43 @@ +var should = require('should'), + vatican = require('../'), + request = require('supertest'); + +describe('vatican configuration', function() { + it('handlers must support a relative path', function( done ) { + var app = new vatican({ + 'handlers': 'fixtures/vaticanConfig/handlers', + 'port': 24000, + }); + + app.start(); + + request('http://localhost:24000') + .get('/people') + .expect(200) + .expect('ok') + .end(function(err) { + ( err == undefined ).should.be.true; + app.close(); + done(); + }); + }); + + it('handlers must support a absolute path', function( done ) { + var app = new vatican({ + 'handlers': __dirname + '/fixtures/vaticanConfig/handlers', + 'port': 24000, + }); + + app.start(); + + request('http://localhost:24000') + .get('/people') + .expect(200) + .expect('ok') + .end(function(err) { + ( err == undefined ).should.be.true; + app.close(); + done(); + }); + }); +});