kibana-123
Version:
Kibana is an open source (Apache Licensed), browser based analytics and search dashboard for Elasticsearch. Kibana is a snap to setup and start using. Kibana strives to be easy to get started with, while also being flexible and powerful, just like Elastic
199 lines (169 loc) • 6.21 kB
JavaScript
import expect from 'expect.js';
import sinon from 'auto-release-sinon';
import cluster from 'cluster';
import { ChildProcess } from 'child_process';
import { difference, findIndex, sample } from 'lodash';
import { fromNode as fn } from 'bluebird';
import MockClusterFork from './_mock_cluster_fork';
import Worker from '../worker';
const workersToShutdown = [];
function assertListenerAdded(emitter, event) {
sinon.assert.calledWith(emitter.on, event);
}
function assertListenerRemoved(emitter, event) {
sinon.assert.calledWith(
emitter.removeListener,
event,
emitter.on.args[findIndex(emitter.on.args, { 0: event })][1]
);
}
function setup(opts = {}) {
sinon.stub(cluster, 'fork', function () {
return new MockClusterFork();
});
const worker = new Worker(opts);
workersToShutdown.push(worker);
return worker;
}
describe('CLI cluster manager', function () {
afterEach(async function () {
for (const worker of workersToShutdown) {
if (worker.shutdown.restore) {
// if the shutdown method was stubbed, restore it first
worker.shutdown.restore();
}
await worker.shutdown();
}
});
describe('#onChange', function () {
context('opts.watch = true', function () {
it('restarts the fork', function () {
const worker = setup({ watch: true });
sinon.stub(worker, 'start');
worker.onChange('/some/path');
expect(worker.changes).to.eql(['/some/path']);
sinon.assert.calledOnce(worker.start);
});
});
context('opts.watch = false', function () {
it('does not restart the fork', function () {
const worker = setup({ watch: false });
sinon.stub(worker, 'start');
worker.onChange('/some/path');
expect(worker.changes).to.eql([]);
sinon.assert.notCalled(worker.start);
});
});
});
describe('#shutdown', function () {
context('after starting()', function () {
it('kills the worker and unbinds from message, online, and disconnect events', async function () {
const worker = setup();
await worker.start();
expect(worker).to.have.property('online', true);
const fork = worker.fork;
sinon.assert.notCalled(fork.process.kill);
assertListenerAdded(fork, 'message');
assertListenerAdded(fork, 'online');
assertListenerAdded(fork, 'disconnect');
worker.shutdown();
sinon.assert.calledOnce(fork.process.kill);
assertListenerRemoved(fork, 'message');
assertListenerRemoved(fork, 'online');
assertListenerRemoved(fork, 'disconnect');
});
});
context('before being started', function () {
it('does nothing', function () {
const worker = setup();
worker.shutdown();
});
});
});
describe('#parseIncomingMessage()', function () {
context('on a started worker', function () {
it(`is bound to fork's message event`, async function () {
const worker = setup();
await worker.start();
sinon.assert.calledWith(worker.fork.on, 'message');
});
});
it('ignores non-array messsages', function () {
const worker = setup();
worker.parseIncomingMessage('some string thing');
worker.parseIncomingMessage(0);
worker.parseIncomingMessage(null);
worker.parseIncomingMessage(undefined);
worker.parseIncomingMessage({ like: 'an object' });
worker.parseIncomingMessage(/weird/);
});
it('calls #onMessage with message parts', function () {
const worker = setup();
const stub = sinon.stub(worker, 'onMessage');
worker.parseIncomingMessage([10, 100, 1000, 10000]);
sinon.assert.calledWith(stub, 10, 100, 1000, 10000);
});
});
describe('#onMessage', function () {
context('when sent WORKER_BROADCAST message', function () {
it('emits the data to be broadcasted', function () {
const worker = setup();
const data = {};
const stub = sinon.stub(worker, 'emit');
worker.onMessage('WORKER_BROADCAST', data);
sinon.assert.calledWithExactly(stub, 'broadcast', data);
});
});
context('when sent WORKER_LISTENING message', function () {
it('sets the listening flag and emits the listening event', function () {
const worker = setup();
const data = {};
const stub = sinon.stub(worker, 'emit');
expect(worker).to.have.property('listening', false);
worker.onMessage('WORKER_LISTENING');
expect(worker).to.have.property('listening', true);
sinon.assert.calledWithExactly(stub, 'listening');
});
});
context('when passed an unkown message', function () {
it('does nothing', function () {
const worker = setup();
worker.onMessage('asdlfkajsdfahsdfiohuasdofihsdoif');
worker.onMessage({});
worker.onMessage(23049283094);
});
});
});
describe('#start', function () {
context('when not started', function () {
it('creates a fork and waits for it to come online', async function () {
const worker = setup();
sinon.spy(worker, 'on');
await worker.start();
sinon.assert.calledOnce(cluster.fork);
sinon.assert.calledWith(worker.on, 'fork:online');
});
it('listens for cluster and process "exit" events', async function () {
const worker = setup();
sinon.spy(process, 'on');
sinon.spy(cluster, 'on');
await worker.start();
sinon.assert.calledOnce(cluster.on);
sinon.assert.calledWith(cluster.on, 'exit');
sinon.assert.calledOnce(process.on);
sinon.assert.calledWith(process.on, 'exit');
});
});
context('when already started', function () {
it('calls shutdown and waits for the graceful shutdown to cause a restart', async function () {
const worker = setup();
await worker.start();
sinon.spy(worker, 'shutdown');
sinon.spy(worker, 'on');
worker.start();
sinon.assert.calledOnce(worker.shutdown);
sinon.assert.calledWith(worker.on, 'online');
});
});
});
});