UNPKG

happner

Version:

distributed application engine with evented storage and mesh services

847 lines (602 loc) 21.1 kB
/* RUN: LOG_LEVEL=off mocha test/18-exchange-promises.js */ var Promise = require('bluebird'); var sep = require('path').sep; var spawn = require('child_process').spawn; module.exports = SeeAbove; function SeeAbove() { } SeeAbove.prototype.method1 = function (opts, callback) { if (opts.errorAs == 'callback') return callback(new Error('THIS IS JUST A TEST')); if (opts.errorAs == 'throw') throw new Error('THIS IS JUST A TEST'); opts.number++; callback(null, opts); }; SeeAbove.prototype.method2 = function (opts, callback) { if (opts.errorAs == 'callback') return callback(new Error('THIS IS JUST A TEST')); if (opts.errorAs == 'throw') throw new Error('THIS IS JUST A TEST'); opts.number++; callback(null, opts); }; SeeAbove.prototype.method3 = function ($happn, $origin, opts, callback) { if (opts.errorAs == 'callback') return callback(new Error('THIS IS JUST A TEST')); if (opts.errorAs == 'throw') throw new Error('THIS IS JUST A TEST'); opts.number++; callback(null, opts); }; SeeAbove.prototype.synchronousMethod = function(opts, opts2){ return opts + opts2; }; SeeAbove.prototype.$happner = { config: { 'testComponent': { schema: { methods: { 'methodName1': { alias: 'ancientmoth' }, 'methodName2': { alias: 'ancientmoth' }, 'synchronousMethod': { type: 'sync-promise'//NB - this is how you can wrap a synchronous method with a promise } } } } } }; if (global.TESTING_E3B) return; // When 'requiring' the module above, describe('e3b-rest-component-secure', function () { /** * Simon Bishop * @type {expect} */ // Uses unit test 2 modules var expect = require('expect.js'); var Mesh = require('../'); var libFolder = __dirname + sep + 'lib' + sep; //var REMOTE_MESH = 'e2-remote-mesh'; var REMOTE_MESH = 'e3-remote-mesh-secure'; var ADMIN_PASSWORD = 'ADMIN_PASSWORD'; require('benchmarket').start(); after(require('benchmarket').store()); this.timeout(120000); var mesh; var remote; var startRemoteMesh = function(callback){ var timedOut = setTimeout(function(){ callback(new Error('remote mesh start timed out')); },5000); // spawn remote mesh in another process remote = spawn('node', [libFolder + REMOTE_MESH]); remote.stdout.on('data', function (data) { if (data.toString().match(/READY/)) { clearTimeout(timedOut); setTimeout(function(){ callback(); },1000); } }); }; before(function (done) { global.TESTING_E3B = true; //............. startRemoteMesh(function(e){ if (e) return done(e); Mesh.create({ name:'e3b-test', datalayer:{ secure:true, adminPassword: ADMIN_PASSWORD, port: 10000 }, util: { // logger: {} }, modules: { 'testComponent': { path: __filename // ............. } }, components: { 'testComponent': {} }, endpoints:{ 'remoteMesh': { // remote mesh node config: { secure:true, port: 10001, host: 'localhost', username:'_ADMIN', password:'happn' } } } }, function (err, instance) { delete global.TESTING_E3B; //............. mesh = instance; if (err) return done(err); mesh.exchange.remoteMesh.remoteComponent.remoteFunction('one','two','three', function(err, result){ if (err) return done(err); done(); }); }); }); }); after(function (done) { this.timeout(30000); if (remote) remote.kill(); if (mesh) mesh.stop({reconnect: false}, done); }); var happnUtils = require('../lib/system/utilities'); var mock$Happn = { datalayer:{ }, _mesh:{ utilities:happnUtils, config:{ name:'e3b-test', datalayer:{ secure:true, port: 10000 } }, description:{ name:'e3b-test' }, endpoints:{}, datalayer:{ server:{ services:{} } } }, exchange:{ testComponent:{ method1:function(opts, callback){ opts.number++; callback(null, opts); } } } }; var mock$Origin = { test:"data" }; var mockResponse = { writeHead:function(code, header){ this.header = {code:code, header:header}; } }; it('tests the rest components __respond method', function(done){ var RestModule = require('../lib/modules/rest/index.js'); var restModule = new RestModule(); var testStage = 'success'; mockResponse.end = function(responseString){ try{ if (testStage == "done") return; var response = JSON.parse(responseString); //TODO: an unexpected GET or POST with a non-json content if (testStage == 'success'){ expect(response.message).to.be("test success response"); expect(response.data.test).to.be("data"); testStage = 'error'; restModule.__respond(mock$Happn, 'test success response', {"test":"data"}, new Error('a test error'), mockResponse); } if (testStage == 'error'){ expect(response.error).to.not.be(null); expect(response.error.message).to.be('a test error'); testStage = "done"; done(); } }catch(e){ done(e); } }; restModule.__respond(mock$Happn, 'test success response', {"test":"data"}, null, mockResponse); }); it('tests the rest components __parseBody method', function(done){ var RestModule = require('../lib/modules/rest/index.js'); var restModule = new RestModule(); var MockRequest = require('./lib/helper_mock_req'); var request = new MockRequest({ method: 'POST', url: '/rest/api', headers: { 'Accept': 'application/json' } }); request.write({ uri:'/testComponent/methodName1', parameters:{ 'opts':{ number:1 } } }); request.end(); mockResponse.end = function(responseString){ var response = JSON.parse(responseString); if (!response.error) return done(new Error('bad response expected error')); done(new Error(response.error)); }; restModule.__parseBody(request, mockResponse, mock$Happn, function(body){ expect(body).to.not.be(null); expect(body).to.not.be(undefined); expect(body.uri).to.be('/testComponent/methodName1'); expect(body.parameters['opts'].number).to.be(1); done(); }); }); var mockLogin = function(restModule, done){ if (!mock$Happn._mesh.datalayer) mock$Happn._mesh.datalayer = {}; if (!mock$Happn._mesh.datalayer.server) mock$Happn._mesh.datalayer.server = {}; if (!mock$Happn._mesh.datalayer.server.services) mock$Happn._mesh.datalayer.server.services = {}; if (!mock$Happn._mesh.datalayer.server.services.security) mock$Happn._mesh.datalayer.server.services.security = {}; mock$Happn._mesh.datalayer.server.services.security.authorize = function(origin, accessPoint, action, callback){ try{ expect(origin.test).to.be("data"); expect(action).to.be("set"); callback(); }catch(e){ callback(e); } }; mock$Happn._mesh.datalayer.server.services.security.login = function(opts, callback){ try{ callback(null, {token:'test'}); }catch(e){ callback(e); } }; restModule.initialize(mock$Happn, function(e){ if (e) return done(e); var MockRequest = require('./lib/helper_mock_req'); var request = new MockRequest({ method: 'POST', url: '/rest/login', headers: { 'Accept': 'application/json' } }); request.write({ username:'_ADMIN', password:ADMIN_PASSWORD }); request.end(); mockResponse.end = function(responseString){ var response = JSON.parse(responseString); if (response.error) return done(new Error(response.error.message)); expect(response.data.token).to.not.be(null); done(); }; restModule.login(mock$Happn, request, mockResponse); }); }; it('tests the rest components login method', function(done){ var RestModule = require('../lib/modules/rest/index.js'); var restModule = new RestModule(); mockLogin(restModule, done); }); var login = function(done, credentials){ var restClient = require('restler'); var operation = { username:'_ADMIN', password:ADMIN_PASSWORD }; if (credentials) operation = credentials; restClient.postJson('http://localhost:10000/rest/login', operation).on('complete', function(result){ if (result.error) return done(new Error(result.error.message)); done(null, result); }); }; it('tests the rest components login method over the wire', function(done){ login(function(e, response){ if (e) return done(e); expect(response.data.token).to.not.be(null); done(); }); }); it('tests the rest components authorize method, successful', function(done){ var RestModule = require('../lib/modules/rest/index.js'); var restModule = new RestModule(); //$happn._mesh.datalayer.services.security mockLogin(restModule, function(e){ if (e) return done(e); //req, res, $happn, $origin, uri, successful mock$Happn._mesh.datalayer.server.services.security = { authorize:function(origin, accessPoint, action, callback){ try{ expect(origin.test).to.be("data"); expect(accessPoint).to.be("/_exchange/requests/e3b-test/test/method"); expect(action).to.be("set"); callback(null, true); }catch(e){ callback(e); } } }; var MockRequest = require('./lib/helper_mock_req'); var request = new MockRequest({ method: 'POST', url: '/rest/api', headers: { 'Accept': 'application/json' } }); request.write({ uri:'/testComponent/methodName1', parameters:{ 'opts':{ number:1 } } }); mockResponse.end = function(responseString){ done(new Error('this was not meant to happn: ' + responseString)); }; restModule.__securityService = mock$Happn._mesh.datalayer.server.services.security; restModule.__authorize(request, mockResponse, mock$Happn, mock$Origin, 'test/method', done); }); }); it('tests the rest components describe method over the api', function(done){ var restClient = require('restler'); login(function(e, result){ if (e) return done(e); restClient.get('http://localhost:10000/rest/describe?happn_token=' + result.data.token).on('complete', function(result){ expect(result.data['/testComponent/method1']).to.not.be(null); expect(result.data['/testComponent/method2']).to.not.be(null); done(); }); }); }); it('tests the rest components handleRequest method', function(done){ var RestModule = require('../lib/modules/rest/index.js'); var restModule = new RestModule(); var MockRequest = require('./lib/helper_mock_req'); var request = new MockRequest({ method: 'POST', url: '/testComponent/method1', headers: { 'Accept': 'application/json' } }); var operation = { parameters:{ 'opts':{'number':1} } }; request.write(operation); request.end(); mockLogin(restModule, function(e){ if (e) return done(e); mock$Happn._mesh.datalayer.server.services.security = { authorize:function(origin, accessPoint, action, callback){ callback(null, true); } }; restModule.__securityService = mock$Happn._mesh.datalayer.server.services.security; mockResponse.end = function(responseString){ var response = JSON.parse(responseString); expect(response.data.number).to.be(2); done(); }; restModule.__exchangeDescription = { components:{ testComponent:{ methods:{ method1:{ parameters:[ {name:'opts'}, {name:'callback'} ] } } } } }; restModule.handleRequest(request, mockResponse, mock$Happn, mock$Origin); }); }); it('tests posting an operation to a local method', function(done){ //TODO login function gives us a token, token is used in body of rest request login(function(e, result){ if (e) return done(e); var restClient = require('restler'); var operation = { parameters:{ 'opts':{'number':1} } }; restClient.postJson('http://localhost:10000/rest/method/testComponent/method1?happn_token=' + result.data.token, operation).on('complete', function(result){ expect(result.data.number).to.be(2); done(); }); }); }); it('tests posting an operation to the security component fails', function(done){ //TODO login function gives us a token, token is used in body of rest request login(function(e, result){ if (e) return done(e); var restClient = require('restler'); var operation = { parameters:{ 'username':'_ADMIN', 'password':'blah' } }; restClient.postJson('http://localhost:10000/rest/method/security/updateOwnUser?happn_token=' + result.data.token, operation).on('complete', function(result){ expect(result.error.number).to.not.be(null); expect(result.error.message).to.be('attempt to access security component over rest'); done(); }); }); }); it('tests posting an operation to a remote method fails', function(done){ //TODO login function gives us a token, token is used in body of rest request login(function(e, result){ if (e) return done(e); var restClient = require('restler'); var operation = { parameters:{ 'one':'one', 'two':'two', 'three':'three' } }; restClient.postJson('http://localhost:10000/rest/method/remoteMesh/remoteComponent/remoteFunction?happn_token=' + result.data.token, operation).on('complete', function(result){ expect(result.error).to.not.be(null); expect(result.error.message).to.be('attempt to access remote mesh: remoteMesh'); done(); }); }); }); it('creates a test user, fails to log in, add group with web permission and log in ok', function (done) { var testAdminClient = new Mesh.MeshClient({secure: true, port: 10000}); var testGroup = { name: 'REST', permissions: { methods: { '/testComponent/method1':{authorized:true} }, web: { '/rest/describe':{actions: ['get'], description: 'rest describe permission'}, '/rest/api':{actions: ['post'], description: 'rest post permission'} } } }; var testGroupSaved; var testUserSaved; var credentials = { username: '_ADMIN', // pending password: ADMIN_PASSWORD }; testAdminClient.login(credentials).then(function () { testAdminClient.exchange.security.addGroup(testGroup, function (e, result) { if (e) return done(e); testGroupSaved = result; var testUser = { username: 'RESTTEST', password: 'REST_TEST' }; testAdminClient.exchange.security.addUser(testUser, function (e, result) { if (e) return done(e); testUserSaved = result; testAdminClient.exchange.security.linkGroup(testGroupSaved, testUserSaved, function (e) { if (e) return done(e); login(function(e, response){ if (e) return done(e); var token = response.data.token; var restClient = require('restler'); restClient.get('http://localhost:10000/rest/describe?happn_token=' + token).on('complete', function(result){ expect(result.data['/security/updateOwnUser']).to.be(undefined); expect(result.data['/remoteMesh/security/updateOwnUser']).to.be(undefined); expect(result.data['/testComponent/method1']).to.not.be(null); expect(result.data['/testComponent/method2']).to.be(undefined); expect(Object.keys(result.data).length).to.be(1); var operation = { parameters:{ 'opts':{number:1} } }; restClient.postJson('http://localhost:10000/rest/method/testComponent/method1?happn_token=' + token, operation).on('complete', function(result){ expect(result.data.number).to.be(2); done(); }); }); }, testUser); }); }); }); }).catch(done); }); it('creates a test user, logs in, but fails to access a method via REST', function (done) { var testAdminClient = new Mesh.MeshClient({secure: true, port: 10000}); var testGroup = { name: 'REST-2', permissions: { methods: { '/remoteMesh/remoteComponent/remoteFunction':{authorized:true}, '/testComponent/method2':{authorized:true} }, web: { '/rest/describe':{actions: ['get'], description: 'rest describe permission'}, '/rest/api':{actions: ['post'], description: 'rest post permission'} } } }; var testGroupSaved; var testUserSaved; var credentials = { username: '_ADMIN', // pending password: ADMIN_PASSWORD }; testAdminClient.login(credentials).then(function () { testAdminClient.exchange.security.addGroup(testGroup, function (e, result) { if (e) return done(e); testGroupSaved = result; var testRESTUser = { username: 'RESTTEST2', password: 'REST_TEST2' }; testAdminClient.exchange.security.addUser(testRESTUser, function (e, result) { if (e) return done(e); testUserSaved = result; testAdminClient.exchange.security.linkGroup(testGroupSaved, testUserSaved, function (e) { if (e) return done(e); login(function(e, response){ if (e) return done(e); var token = response.data.token; var restClient = require('restler'); var operation = { parameters:{ 'opts':{ number:1 } } }; //this call fails restClient.postJson('http://localhost:10000/rest/method/testComponent/method1?happn_token=' + token, operation).on('complete', function(result){ expect(result.error).to.not.be(null); expect(result.error.message).to.be('Access denied'); var operation = { parameters:{ 'opts':{ number:1 } } }; //this call works restClient.postJson('http://localhost:10000/rest/method/testComponent/method2?happn_token=' + token, operation).on('complete', function(result){ expect(result.error).to.be(null); expect(result.data.number).to.be(2); testGroup.permissions.methods['/testComponent/method2'] = {authorized:false}; testAdminClient.exchange.security.updateGroup(testGroup, function (e, result) { if (e) return done(e); var operation = { parameters:{ 'opts':{ number:1 } } }; //this call stops working restClient.postJson('http://localhost:10000/rest/method/testComponent/method2?happn_token=' + token, operation).on('complete', function(result){ expect(result.error).to.not.be(null); expect(result.error.message).to.be('Access denied'); done(); }); }); }); }); }, testRESTUser); }); }); }); }).catch(done); }); require('benchmarket').stop(); });