2015-08-28 10:54:29 -07:00
|
|
|
'use strict';
|
|
|
|
|
|
|
|
var should = require('chai').should();
|
|
|
|
var sinon = require('sinon');
|
|
|
|
var EventEmitter = require('events').EventEmitter;
|
2015-09-09 13:39:21 -07:00
|
|
|
var proxyquire = require('proxyquire');
|
|
|
|
|
|
|
|
var httpStub = {
|
|
|
|
createServer: sinon.spy()
|
|
|
|
};
|
|
|
|
var httpsStub = {
|
|
|
|
createServer: sinon.spy()
|
|
|
|
};
|
|
|
|
var fsStub = {
|
|
|
|
readFileSync: function(arg1) {
|
|
|
|
return arg1 + '-buffer';
|
|
|
|
}
|
|
|
|
};
|
|
|
|
|
2015-09-10 08:06:37 -07:00
|
|
|
var fakeSocketListener = new EventEmitter();
|
|
|
|
var fakeSocket = new EventEmitter();
|
|
|
|
|
|
|
|
fakeSocket.on('test/event1', function(data) {
|
|
|
|
data.should.equal('testdata');
|
|
|
|
done();
|
|
|
|
});
|
|
|
|
|
|
|
|
fakeSocketListener.emit('connection', fakeSocket);
|
|
|
|
|
|
|
|
fakeSocket.emit('subscribe', 'test/event1');
|
|
|
|
|
|
|
|
|
|
|
|
|
2015-09-09 13:39:21 -07:00
|
|
|
var WebService = proxyquire('../../lib/services/web', {http: httpStub, https: httpsStub, fs: fsStub});
|
2015-08-28 10:54:29 -07:00
|
|
|
|
|
|
|
describe('WebService', function() {
|
|
|
|
var defaultNode = new EventEmitter();
|
|
|
|
|
2016-04-15 07:44:56 -07:00
|
|
|
describe('@constructor', function() {
|
|
|
|
it('will set socket rpc settings', function() {
|
|
|
|
var web = new WebService({node: defaultNode, enableSocketRPC: false});
|
|
|
|
web.enableSocketRPC.should.equal(false);
|
|
|
|
|
|
|
|
var web2 = new WebService({node: defaultNode, enableSocketRPC: true});
|
|
|
|
web2.enableSocketRPC.should.equal(true);
|
|
|
|
|
|
|
|
var web3 = new WebService({node: defaultNode});
|
|
|
|
web3.enableSocketRPC.should.equal(WebService.DEFAULT_SOCKET_RPC);
|
|
|
|
});
|
|
|
|
});
|
|
|
|
|
2015-08-28 10:54:29 -07:00
|
|
|
describe('#start', function() {
|
2015-09-09 13:39:21 -07:00
|
|
|
beforeEach(function() {
|
|
|
|
httpStub.createServer.reset();
|
|
|
|
httpsStub.createServer.reset();
|
|
|
|
});
|
2015-09-10 08:06:37 -07:00
|
|
|
it('should create an http server if no options are specified and node is not configured for https', function(done) {
|
|
|
|
var web = new WebService({node: defaultNode});
|
2015-09-09 13:39:21 -07:00
|
|
|
web.deriveHttpsOptions = sinon.spy();
|
2015-08-28 10:54:29 -07:00
|
|
|
web.start(function(err) {
|
|
|
|
should.not.exist(err);
|
2015-09-09 13:39:21 -07:00
|
|
|
httpStub.createServer.called.should.equal(true);
|
|
|
|
done();
|
|
|
|
});
|
|
|
|
});
|
|
|
|
|
2015-09-10 08:06:37 -07:00
|
|
|
it('should create an https server if no options are specified and node is configured for https', function(done) {
|
2015-09-09 13:39:21 -07:00
|
|
|
var node = new EventEmitter();
|
2015-09-10 08:06:37 -07:00
|
|
|
node.https = true;
|
2015-09-09 13:39:21 -07:00
|
|
|
|
|
|
|
var web = new WebService({node: node});
|
2015-09-10 08:06:37 -07:00
|
|
|
web.transformHttpsOptions = sinon.spy();
|
2015-09-09 13:39:21 -07:00
|
|
|
web.start(function(err) {
|
|
|
|
should.not.exist(err);
|
|
|
|
httpsStub.createServer.called.should.equal(true);
|
2015-08-28 10:54:29 -07:00
|
|
|
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();
|
|
|
|
});
|
|
|
|
});
|
|
|
|
});
|
|
|
|
|
2015-08-31 10:05:46 -07:00
|
|
|
describe('#setupAllRoutes', function() {
|
2015-08-28 10:54:29 -07:00
|
|
|
it('should call setupRoutes on each module', function() {
|
|
|
|
var node = {
|
|
|
|
on: sinon.spy(),
|
2015-08-31 10:38:21 -07:00
|
|
|
services: {
|
2015-08-28 10:54:29 -07:00
|
|
|
one: {
|
2015-09-03 13:38:23 -07:00
|
|
|
setupRoutes: sinon.spy(),
|
|
|
|
getRoutePrefix: sinon.stub().returns('one')
|
2015-08-28 10:54:29 -07:00
|
|
|
},
|
|
|
|
two: {
|
2015-09-03 13:38:23 -07:00
|
|
|
setupRoutes: sinon.spy(),
|
|
|
|
getRoutePrefix: sinon.stub().returns('two')
|
2015-08-28 10:54:29 -07:00
|
|
|
}
|
|
|
|
}
|
|
|
|
};
|
|
|
|
|
|
|
|
var web = new WebService({node: node});
|
2015-09-03 13:38:23 -07:00
|
|
|
web.app = {
|
|
|
|
use: sinon.spy()
|
|
|
|
};
|
2015-08-28 10:54:29 -07:00
|
|
|
|
2015-08-31 10:05:46 -07:00
|
|
|
web.setupAllRoutes();
|
2015-08-31 10:38:21 -07:00
|
|
|
node.services.one.setupRoutes.callCount.should.equal(1);
|
2015-11-03 07:32:01 -08:00
|
|
|
should.exist(node.services.one.setupRoutes.args[0][0].engine);
|
|
|
|
should.exist(node.services.one.setupRoutes.args[0][0].get);
|
|
|
|
should.exist(node.services.one.setupRoutes.args[0][0].post);
|
|
|
|
should.exist(node.services.one.setupRoutes.args[0][0].set);
|
2015-08-31 10:38:21 -07:00
|
|
|
node.services.two.setupRoutes.callCount.should.equal(1);
|
2015-08-28 10:54:29 -07:00
|
|
|
});
|
|
|
|
});
|
|
|
|
|
|
|
|
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();
|
|
|
|
});
|
|
|
|
});
|
|
|
|
});
|
|
|
|
});
|
|
|
|
|
2015-09-03 14:29:28 -07:00
|
|
|
describe('#getEventNames', function() {
|
|
|
|
it('should get event names', function() {
|
|
|
|
var Module1 = function() {};
|
|
|
|
Module1.prototype.getPublishEvents = function() {
|
|
|
|
return [
|
|
|
|
{
|
|
|
|
name: 'event1',
|
|
|
|
extraEvents: ['event2']
|
|
|
|
}
|
|
|
|
];
|
|
|
|
};
|
|
|
|
|
|
|
|
var module1 = new Module1();
|
|
|
|
var node = {
|
|
|
|
on: sinon.spy(),
|
|
|
|
getAllPublishEvents: sinon.stub().returns(module1.getPublishEvents())
|
|
|
|
};
|
|
|
|
|
|
|
|
var web = new WebService({node: node});
|
|
|
|
var events = web.getEventNames();
|
|
|
|
|
|
|
|
events.should.deep.equal(['event1', 'event2']);
|
|
|
|
});
|
|
|
|
|
|
|
|
it('should throw an error if there is a duplicate event', function() {
|
|
|
|
var Module1 = function() {};
|
|
|
|
Module1.prototype.getPublishEvents = function() {
|
|
|
|
return [
|
|
|
|
{
|
|
|
|
name: 'event1',
|
|
|
|
extraEvents: ['event1']
|
|
|
|
}
|
|
|
|
];
|
|
|
|
};
|
|
|
|
|
|
|
|
var module1 = new Module1();
|
|
|
|
var node = {
|
|
|
|
on: sinon.spy(),
|
|
|
|
getAllPublishEvents: sinon.stub().returns(module1.getPublishEvents())
|
|
|
|
};
|
|
|
|
|
|
|
|
var web = new WebService({node: node});
|
|
|
|
(function() {
|
|
|
|
var events = web.getEventNames();
|
|
|
|
}).should.throw('Duplicate event event1');
|
|
|
|
});
|
|
|
|
});
|
|
|
|
|
2015-08-28 10:54:29 -07:00
|
|
|
describe('#socketHandler', function() {
|
|
|
|
var bus = new EventEmitter();
|
|
|
|
|
|
|
|
var Module1 = function() {};
|
|
|
|
Module1.prototype.getPublishEvents = function() {
|
|
|
|
return [
|
|
|
|
{
|
2015-09-03 13:38:23 -07:00
|
|
|
name: 'event1',
|
|
|
|
extraEvents: ['event2']
|
2015-08-28 10:54:29 -07:00
|
|
|
}
|
|
|
|
];
|
|
|
|
};
|
|
|
|
|
|
|
|
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});
|
2015-09-03 14:29:28 -07:00
|
|
|
web.eventNames = web.getEventNames();
|
2015-08-28 10:54:29 -07:00
|
|
|
web.socketMessageHandler = function(param1) {
|
|
|
|
param1.should.equal('data');
|
|
|
|
done();
|
|
|
|
};
|
|
|
|
socket = new EventEmitter();
|
|
|
|
web.socketHandler(socket);
|
|
|
|
socket.emit('message', 'data');
|
|
|
|
});
|
|
|
|
|
2016-04-15 07:44:56 -07:00
|
|
|
it('on message should NOT call socketMessageHandler if not enabled', function(done) {
|
|
|
|
web = new WebService({node: node, enableSocketRPC: false});
|
|
|
|
web.eventNames = web.getEventNames();
|
|
|
|
web.socketMessageHandler = sinon.stub();
|
|
|
|
socket = new EventEmitter();
|
|
|
|
web.socketHandler(socket);
|
|
|
|
socket.on('message', function() {
|
|
|
|
web.socketMessageHandler.callCount.should.equal(0);
|
|
|
|
done();
|
|
|
|
});
|
|
|
|
socket.emit('message', 'data');
|
|
|
|
});
|
|
|
|
|
2015-08-28 10:54:29 -07:00
|
|
|
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) {
|
2015-09-03 13:38:23 -07:00
|
|
|
socket.once('event2', function(param1, param2) {
|
2015-08-28 10:54:29 -07:00
|
|
|
param1.should.equal('param1');
|
|
|
|
param2.should.equal('param2');
|
|
|
|
done();
|
|
|
|
});
|
|
|
|
socket.connected = true;
|
2015-09-03 13:38:23 -07:00
|
|
|
bus.emit('event2', 'param1', 'param2');
|
2015-08-28 10:54:29 -07:00
|
|
|
});
|
|
|
|
|
|
|
|
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();
|
|
|
|
});
|
|
|
|
});
|
|
|
|
});
|
|
|
|
|
2015-09-09 13:39:21 -07:00
|
|
|
describe('#deriveHttpsOptions', function() {
|
2015-09-10 08:06:37 -07:00
|
|
|
it('should read key and cert from files specified', function() {
|
2015-09-09 13:39:21 -07:00
|
|
|
var web = new WebService({
|
|
|
|
node: defaultNode,
|
|
|
|
https: true,
|
|
|
|
httpsOptions: {
|
|
|
|
key: 'key',
|
|
|
|
cert: 'cert'
|
|
|
|
}
|
|
|
|
});
|
|
|
|
|
2015-09-10 08:06:37 -07:00
|
|
|
web.transformHttpsOptions();
|
2015-09-09 13:39:21 -07:00
|
|
|
web.httpsOptions.key.should.equal('key-buffer');
|
|
|
|
web.httpsOptions.cert.should.equal('cert-buffer');
|
|
|
|
});
|
|
|
|
it('should throw an error if https is specified but key or cert is not specified', function() {
|
|
|
|
var web = new WebService({
|
|
|
|
node: defaultNode,
|
|
|
|
https: true,
|
|
|
|
httpsOptions: {
|
|
|
|
key: 'key'
|
|
|
|
}
|
|
|
|
});
|
|
|
|
|
|
|
|
(function() {
|
2015-09-10 08:06:37 -07:00
|
|
|
web.transformHttpsOptions();
|
2015-09-09 13:39:21 -07:00
|
|
|
}).should.throw('Missing https options');
|
|
|
|
});
|
|
|
|
});
|
|
|
|
|
2015-11-03 07:32:01 -08:00
|
|
|
});
|