UNPKG

pm25

Version:

Production process manager for Node.JS applications with a built-in load balancer.

259 lines (214 loc) 7 kB
var PM2 = require('../..'); var should = require('should'); var nssocket = require('nssocket'); var events = require('events'); var util = require('util'); var Cipher = require('../../lib/Interactor/Cipher.js'); var cst = require('../../constants.js'); var Plan = require('../helpers/plan.js'); var Configuration = require('../../lib/Configuration.js'); var Helpers = require('../helpers/apps.js'); var Interactor = require('../../lib/Interactor/InteractorDaemonizer.js'); var gl_interactor_process; var send_cmd = new events.EventEmitter(); process.env.NODE_ENV = 'local_test'; var meta_connect = { secret_key : 'test-secret-key', public_key : 'test-public-key', machine_name : 'test-machine-name' }; /** * Description * @method forkInteractor * @return CallExpression */ function forkInteractor(cb) { Interactor.launchAndInteract(meta_connect, function(err, data, interactor_process) { gl_interactor_process = interactor_process; cb(); }); } /** * Mock server receiving data * @method forkInteractor * @return CallExpression */ function createMockServer(cb) { var server = nssocket.createServer(function(_socket) { send_cmd.on('cmd', function(data) { if (process.env.DEBUG) console.log('Sending command %j', data); _socket.send(data._type, data); }); _socket.data('*', function(data) { this.event.forEach(function(ev) { send_cmd.emit(ev, data); }); }); }); server.on('error', function(e) { throw new Error(e); }); server.on('listening', function() { cb(null, server); }); server.listen(4322, '0.0.0.0'); } function startSomeApps(cb) { pm2.start('./child.js', {instances : 1, name : 'child'}, cb); } var pm2 = new PM2.custom({ independent : true, cwd : __dirname + '/../fixtures', secret_key : 'test-secret-key', public_key : 'test-public-key', machine_name : 'test-machine-name', daemon_mode: true }); describe('SCOPED PM2 ACTIONS', function() { var server; var interactor; this.timeout(5000); after(function(done) { server.close(); pm2.destroy(done); }); before(function(done) { createMockServer(function(err, _server) { server = _server; pm2.connect(function() { startSomeApps(function(err) { gl_interactor_process = pm2.Client.interactor_process; // @todo: would be nice to know when an app is ready // @priotity: minor setTimeout(done, 1500); }); }); }); }); it('should send ask, receive ask:rep and identify agent', function(done) { send_cmd.once('ask:rep', function(pck) { var data = Cipher.decipherMessage(pck.data, meta_connect.secret_key); data.machine_name.should.eql(meta_connect.machine_name); done(); }); send_cmd.emit('cmd', { _type : 'ask' }); }); /** * PM2 agent is now identified */ describe('Test non auth remote commands', function() { before(function(done) { Configuration.unset('pm2:passwd', function(err, data) { should.not.exists(err); done(); }); }); it('should restart command via scoped pm2 action (no pass needed)', function(done) { var good = false; var plan = new Plan(2, function() { gl_interactor_process.removeListener('message', actionCheck); good = true; done(); }); function actionCheck(pck) { if (good) return false; if (pck.event == 'pm2:scoped:stream' && pck.data.out === 'Action restart received') return plan.ok(true); if (pck.event == 'pm2:scoped:end') return plan.ok(true); if (pck.event == 'pm2:scoped:error') return plan.ok(false, pck); return false; } gl_interactor_process.on('message', actionCheck); send_cmd.emit('cmd', { _type : 'trigger:pm2:scoped:action', action_name : 'restart', uuid : '1234', options : { args : ['child'] } }); }); }); describe('Password verification', function() { before(function(done) { Configuration.unset('pm2:passwd', function(err, data) { should.not.exists(err); done(); }); }); it('should error when call an action that is password protected', function(done) { function actionCheck(pck) { if (pck.event == 'pm2:scoped:error' && pck.data.out.indexOf('Missing password') > -1) { gl_interactor_process.removeListener('message', actionCheck); done(); } }; gl_interactor_process.on('message', actionCheck); send_cmd.emit('cmd', { _type : 'trigger:pm2:scoped:action', action_name : 'install', uuid : '5678', options : { args : ['child'] } }); }); it('should fail when password passed but no pm2 password configured', function(done) { function actionCheck(pck) { if (pck.event == 'pm2:scoped:error' && pck.data.out.indexOf('Password at PM2') > -1) { gl_interactor_process.removeListener('message', actionCheck); done(); } }; gl_interactor_process.on('message', actionCheck); send_cmd.emit('cmd', { _type : 'trigger:pm2:scoped:action', action_name : 'install', uuid : '5678', password : 'random-pass', options : { args : ['pm2-module'] } }); }); it('should set a password', function(done) { pm2.set('pm2:passwd', 'testpass', function(err, data) { should.not.exists(err); done(); }); }); it('should fail when wrong password', function(done) { function actionCheck(pck) { if (pck.event == 'pm2:scoped:error' && pck.data.out.indexOf('Password does not match') > -1) { gl_interactor_process.removeListener('message', actionCheck); setTimeout(done, 100); } }; gl_interactor_process.on('message', actionCheck); send_cmd.emit('cmd', { _type : 'trigger:pm2:scoped:action', action_name : 'install', uuid : '5678', password : 'random-pass', options : { args : ['pm2-module'] } }); }); it('should work when good password passed', function(done) { function actionCheck(pck) { if (pck.event === 'pm2:scoped:end') { gl_interactor_process.removeListener('message', actionCheck); done(); } if (pck.event === 'pm2:scoped:error') { gl_interactor_process.removeListener('message', actionCheck); done('{ERROR} Wrong password!' + JSON.stringify(pck)); } }; gl_interactor_process.on('message', actionCheck); send_cmd.emit('cmd', { _type : 'trigger:pm2:scoped:action', action_name : 'ping', uuid : '5678', password : 'testpass', options : {} }); }); }); });