From 1b5f30a9a1e70d65b7afdbd074b5250e2ec90824 Mon Sep 17 00:00:00 2001 From: Patrick Nagurny Date: Fri, 28 Aug 2015 13:54:29 -0400 Subject: [PATCH] add tests --- integration/regtest.js | 16 +++ lib/node.js | 1 + lib/web.js | 38 ++++--- test/web.unit.js | 239 +++++++++++++++++++++++++++++++++++++++++ 4 files changed, 277 insertions(+), 17 deletions(-) create mode 100644 test/web.unit.js diff --git a/integration/regtest.js b/integration/regtest.js index 59ca049b..0b8a7291 100644 --- a/integration/regtest.js +++ b/integration/regtest.js @@ -227,11 +227,27 @@ describe('Daemon Binding Functionality', function() { work.cmp(expectedWork).should.equal(0); expectedWork = expectedWork.add(new BN(2)); should.exist(blockIndex.prevHash); + blockIndex.hash.should.equal(blockHashes[i]); blockIndex.prevHash.should.equal(blockHashes[i - 1]); + blockIndex.height.should.equal(i + 1); }); }); }); + describe('get block index by height', function() { + it('should get block index by height', function() { + var blockIndex = bitcoind.getBlockIndex(2); + should.exist(blockIndex); + should.exist(blockIndex.chainWork); + var work = new BN(blockIndex.chainWork, 'hex'); + work.cmp(new BN(8)).should.equal(0); + should.exist(blockIndex.prevHash); + blockIndex.hash.should.equal(blockHashes[1]); + blockIndex.prevHash.should.equal(blockHashes[0]); + blockIndex.height.should.equal(2); + }); + }); + describe('send transaction functionality', function() { it('will not error and return the transaction hash', function() { diff --git a/lib/node.js b/lib/node.js index 31953996..16bf376a 100644 --- a/lib/node.js +++ b/lib/node.js @@ -11,6 +11,7 @@ var log = index.log; var Bus = require('./bus'); var BaseService = require('./service'); var WebService = require('./web'); +var errors = require('./errors'); function Node(config) { if(!(this instanceof Node)) { diff --git a/lib/web.js b/lib/web.js index fd4730a8..e5656608 100644 --- a/lib/web.js +++ b/lib/web.js @@ -13,6 +13,7 @@ var WebService = function(options) { this.node.on('ready', function() { self.setupRoutes(); self.server.listen(self.port); + self.createMethodsMap(); }); }; @@ -26,22 +27,6 @@ WebService.prototype.start = function(callback) { this.io = socketio.listen(this.server); this.io.on('connection', this.socketHandler.bind(this)); - var methods = this.node.getAllAPIMethods(); - this.methodsMap = {}; - - methods.forEach(function(data) { - var name = data[0]; - var instance = data[1]; - var method = data[2]; - var args = data[3]; - self.methodsMap[name] = { - fn: function() { - return method.apply(instance, arguments); - }, - args: args - }; - }); - setImmediate(callback); }; @@ -63,6 +48,25 @@ WebService.prototype.setupRoutes = function() { } }; +WebService.prototype.createMethodsMap = function() { + var self = this; + var methods = this.node.getAllAPIMethods(); + this.methodsMap = {}; + + methods.forEach(function(data) { + var name = data[0]; + var instance = data[1]; + var method = data[2]; + var args = data[3]; + self.methodsMap[name] = { + fn: function() { + return method.apply(instance, arguments); + }, + args: args + }; + }); +} + WebService.prototype.socketHandler = function(socket) { var self = this; @@ -111,7 +115,7 @@ WebService.prototype.socketMessageHandler = function(message, socketCallback) { if(params.length !== this.methodsMap[message.method].args) { return socketCallback({ error: { - message: 'Expected ' + this.methodsMap[message.method].args + ' parameters' + message: 'Expected ' + this.methodsMap[message.method].args + ' parameter(s)' } }); } diff --git a/test/web.unit.js b/test/web.unit.js new file mode 100644 index 00000000..1c283efe --- /dev/null +++ b/test/web.unit.js @@ -0,0 +1,239 @@ +'use strict'; + +var should = require('chai').should(); +var sinon = require('sinon'); +var WebService = require('../lib/web'); +var EventEmitter = require('events').EventEmitter; + +describe('WebService', function() { + var defaultNode = new EventEmitter(); + + describe('#start', function() { + it('should call the callback with no error', function(done) { + var web = new WebService({node: defaultNode}); + web.start(function(err) { + should.not.exist(err); + done(); + }); + }); + }); + + describe('#stop', function() { + it('should close the server if it exists', function(done) { + var web = new WebService({node: defaultNode}); + web.server = { + close: sinon.spy() + }; + + web.stop(function(err) { + should.not.exist(err); + web.server.close.callCount.should.equal(1); + done(); + }); + }); + }); + + describe('#setupRoutes', function() { + it('should call setupRoutes on each module', function() { + var node = { + on: sinon.spy(), + modules: { + one: { + setupRoutes: sinon.spy() + }, + two: { + setupRoutes: sinon.spy() + } + } + }; + + var web = new WebService({node: node}); + + web.setupRoutes(); + node.modules.one.setupRoutes.callCount.should.equal(1); + node.modules.two.setupRoutes.callCount.should.equal(1); + }); + }); + + describe('#createMethodsMap', function() { + it('should create the methodsMap correctly', function(done) { + var Module1 = function() {}; + Module1.prototype.getAPIMethods = function() { + return [ + ['one', this, this.one, 1], + ['two', this, this.two, 2] + ]; + }; + Module1.prototype.one = function(param1, callback) { + callback(null, param1); + }; + Module1.prototype.two = function(param1, param2, callback) { + callback(null, param1 + param2); + }; + + var module1 = new Module1(); + + var node = { + on: sinon.spy(), + getAllAPIMethods: sinon.stub().returns(module1.getAPIMethods()) + }; + + var web = new WebService({node: node}); + web.createMethodsMap(); + + Object.keys(web.methodsMap).length.should.equal(2); + web.methodsMap.one.args.should.equal(1); + web.methodsMap.two.args.should.equal(2); + web.methodsMap.one.fn(1, function(err, result) { + should.not.exist(err); + result.should.equal(1); + + web.methodsMap.two.fn(1, 2, function(err, result) { + should.not.exist(err); + result.should.equal(3); + done(); + }); + }); + }); + }); + + describe('#socketHandler', function() { + var bus = new EventEmitter(); + + var Module1 = function() {}; + Module1.prototype.getPublishEvents = function() { + return [ + { + name: 'event1' + } + ]; + }; + + var module1 = new Module1(); + var node = { + on: sinon.spy(), + openBus: sinon.stub().returns(bus), + getAllPublishEvents: sinon.stub().returns(module1.getPublishEvents()) + }; + + var web; + var socket; + + it('on message should call socketMessageHandler', function(done) { + web = new WebService({node: node}); + web.socketMessageHandler = function(param1) { + param1.should.equal('data'); + done(); + }; + socket = new EventEmitter(); + web.socketHandler(socket); + socket.emit('message', 'data'); + }); + + it('on subscribe should call bus.subscribe', function(done) { + bus.subscribe = function(param1) { + param1.should.equal('data'); + done(); + }; + + socket.emit('subscribe', 'data'); + }); + + it('on unsubscribe should call bus.unsubscribe', function(done) { + bus.unsubscribe = function(param1) { + param1.should.equal('data'); + done(); + }; + + socket.emit('unsubscribe', 'data'); + }); + + it('publish events from bus should be emitted from socket', function(done) { + socket.once('event1', function(param1, param2) { + param1.should.equal('param1'); + param2.should.equal('param2'); + done(); + }); + socket.connected = true; + bus.emit('event1', 'param1', 'param2'); + }); + + it('on disconnect should close bus', function(done) { + bus.close = function() { + done(); + }; + + socket.emit('disconnect'); + }); + }); + + describe('#socketMessageHandler', function() { + var node = { + on: sinon.spy() + }; + + var web = new WebService({node: node}); + web.methodsMap = { + one: { + fn: function(param1, param2, callback) { + var result = param1 + param2; + if(result > 0) { + return callback(null, result); + } else { + return callback(new Error('error')); + } + }, + args: 2 + } + }; + + it('should give a Method Not Found error if method does not exist', function(done) { + var message = { + method: 'two', + params: [1, 2] + } + web.socketMessageHandler(message, function(response) { + should.exist(response.error); + response.error.message.should.equal('Method Not Found'); + done(); + }); + }); + + it('should call the method and return the result', function(done) { + var message = { + method: 'one', + params: [1, 2] + }; + web.socketMessageHandler(message, function(response) { + should.not.exist(response.error); + response.result.should.equal(3); + done(); + }); + }); + + it('should give an error if there is a param count mismatch', function(done) { + var message = { + method: 'one', + params: [1] + }; + web.socketMessageHandler(message, function(response) { + should.exist(response.error); + response.error.message.should.equal('Expected 2 parameter(s)'); + done(); + }); + }); + + it('should give an error if the method gave an error', function(done) { + var message = { + method: 'one', + params: [-1, -2] + }; + web.socketMessageHandler(message, function(response) { + should.exist(response.error); + response.error.message.should.equal('Error: error'); + done(); + }); + }); + }); + +}); \ No newline at end of file