[kbn-es] add basic integration tests for exit code/promise handling (#17600)

This commit is contained in:
Spencer 2018-04-18 12:59:19 -07:00 committed by GitHub
parent d9f34f704e
commit 1fd537821f
No known key found for this signature in database
GPG key ID: 4AEE18F83AFDEB23
3 changed files with 340 additions and 1 deletions

View file

@ -176,7 +176,7 @@ exports.Cluster = class Cluster {
this._process.once('exit', code => {
// JVM exits with 143 on SIGTERM and 130 on SIGINT, dont' treat them as errors
if (code > 0 && !(code === 143 || code === 130)) {
reject(createCliError(`ES exitted with code ${code}`));
reject(createCliError(`ES exited with code ${code}`));
} else {
resolve();
}

View file

@ -0,0 +1,9 @@
#!/usr/bin/env node
const { exitCode, start } = JSON.parse(process.argv[2]);
if (start) {
console.log('started');
}
process.exitCode = exitCode;

View file

@ -0,0 +1,330 @@
const { createToolingLog } = require('@kbn/dev-utils');
const execa = require('execa');
const { Cluster } = require('../cluster');
const {
installSource,
installSnapshot,
installArchive,
} = require('../install');
jest.mock('../install', () => ({
installSource: jest.fn(),
installSnapshot: jest.fn(),
installArchive: jest.fn(),
}));
jest.mock('execa', () => jest.fn());
const log = createToolingLog('verbose');
log.onData = jest.fn();
log.on('data', log.onData);
function sleep(ms) {
return new Promise(resolve => setTimeout(resolve, ms));
}
async function ensureNoResolve(promise) {
await Promise.race([
sleep(100),
promise.then(() => {
throw new Error('promise was not supposed to resolve');
}),
]);
}
async function ensureResolve(promise) {
return await Promise.race([
promise,
sleep(100).then(() => {
throw new Error(
'promise was supposed to resolve with installSource() resolution'
);
}),
]);
}
function mockEsBin({ exitCode, start }) {
execa.mockImplementationOnce((cmd, args, options) =>
require.requireActual('execa')(
process.execPath,
[
require.resolve('./__fixtures__/es_bin.js'),
JSON.stringify({
exitCode,
start,
}),
],
options
)
);
}
beforeEach(() => {
jest.resetAllMocks();
});
describe('#installSource()', () => {
it('awaits installSource() promise and returns { installPath }', async () => {
let resolveInstallSource;
installSource.mockImplementationOnce(
() =>
new Promise(resolve => {
resolveInstallSource = () => {
resolve({ installPath: 'foo' });
};
})
);
const cluster = new Cluster(log);
const promise = cluster.installSource();
await ensureNoResolve(promise);
resolveInstallSource();
await expect(ensureResolve(promise)).resolves.toEqual({
installPath: 'foo',
});
});
it('passes through all options+log to installSource()', async () => {
installSource.mockResolvedValue({});
const cluster = new Cluster(log);
await cluster.installSource({ foo: 'bar' });
expect(installSource).toHaveBeenCalledTimes(1);
expect(installSource).toHaveBeenCalledWith({
log,
foo: 'bar',
});
});
it('rejects if installSource() rejects', async () => {
installSource.mockRejectedValue(new Error('foo'));
const cluster = new Cluster(log);
await expect(cluster.installSource()).rejects.toThrowError('foo');
});
});
describe('#installSnapshot()', () => {
it('awaits installSnapshot() promise and returns { installPath }', async () => {
let resolveInstallSnapshot;
installSnapshot.mockImplementationOnce(
() =>
new Promise(resolve => {
resolveInstallSnapshot = () => {
resolve({ installPath: 'foo' });
};
})
);
const cluster = new Cluster(log);
const promise = cluster.installSnapshot();
await ensureNoResolve(promise);
resolveInstallSnapshot();
await expect(ensureResolve(promise)).resolves.toEqual({
installPath: 'foo',
});
});
it('passes through all options+log to installSnapshot()', async () => {
installSnapshot.mockResolvedValue({});
const cluster = new Cluster(log);
await cluster.installSnapshot({ foo: 'bar' });
expect(installSnapshot).toHaveBeenCalledTimes(1);
expect(installSnapshot).toHaveBeenCalledWith({
log,
foo: 'bar',
});
});
it('rejects if installSnapshot() rejects', async () => {
installSnapshot.mockRejectedValue(new Error('foo'));
const cluster = new Cluster(log);
await expect(cluster.installSnapshot()).rejects.toThrowError('foo');
});
});
describe('#installArchive(path)', () => {
it('awaits installArchive() promise and returns { installPath }', async () => {
let resolveInstallArchive;
installArchive.mockImplementationOnce(
() =>
new Promise(resolve => {
resolveInstallArchive = () => {
resolve({ installPath: 'foo' });
};
})
);
const cluster = new Cluster(log);
const promise = cluster.installArchive();
await ensureNoResolve(promise);
resolveInstallArchive();
await expect(ensureResolve(promise)).resolves.toEqual({
installPath: 'foo',
});
});
it('passes through path and all options+log to installArchive()', async () => {
installArchive.mockResolvedValue({});
const cluster = new Cluster(log);
await cluster.installArchive('path', { foo: 'bar' });
expect(installArchive).toHaveBeenCalledTimes(1);
expect(installArchive).toHaveBeenCalledWith('path', {
log,
foo: 'bar',
});
});
it('rejects if installArchive() rejects', async () => {
installArchive.mockRejectedValue(new Error('foo'));
const cluster = new Cluster(log);
await expect(cluster.installArchive()).rejects.toThrowError('foo');
});
});
describe('#start(installPath)', () => {
it('rejects when bin/elasticsearch exists with 0 before starting', async () => {
mockEsBin({ exitCode: 0, start: false });
await expect(new Cluster(log).start()).rejects.toThrowError(
'ES exited without starting'
);
});
it('rejects when bin/elasticsearch exists with 143 before starting', async () => {
mockEsBin({ exitCode: 143, start: false });
await expect(new Cluster(log).start()).rejects.toThrowError(
'ES exited without starting'
);
});
it('rejects when bin/elasticsearch exists with 130 before starting', async () => {
mockEsBin({ exitCode: 130, start: false });
await expect(new Cluster(log).start()).rejects.toThrowError(
'ES exited without starting'
);
});
it('rejects when bin/elasticsearch exists with 1 before starting', async () => {
mockEsBin({ exitCode: 1, start: false });
await expect(new Cluster(log).start()).rejects.toThrowError(
'ES exited with code 1'
);
});
it('resolves when bin/elasticsearch logs "started"', async () => {
mockEsBin({ start: true });
await new Cluster(log).start();
});
it('rejects if #start() was called previously', async () => {
mockEsBin({ start: true });
const cluster = new Cluster(log);
await cluster.start();
await expect(cluster.start()).rejects.toThrowError(
'ES has already been started'
);
});
it('rejects if #run() was called previously', async () => {
mockEsBin({ start: true });
const cluster = new Cluster(log);
await cluster.run();
await expect(cluster.start()).rejects.toThrowError(
'ES has already been started'
);
});
});
describe('#run()', () => {
it('resolves when bin/elasticsearch exists with 0', async () => {
mockEsBin({ exitCode: 0 });
await new Cluster(log).run();
});
it('resolves when bin/elasticsearch exists with 143', async () => {
mockEsBin({ exitCode: 143 });
await new Cluster(log).run();
});
it('resolves when bin/elasticsearch exists with 130', async () => {
mockEsBin({ exitCode: 130 });
await new Cluster(log).run();
});
it('rejects when bin/elasticsearch exists with 1', async () => {
mockEsBin({ exitCode: 1 });
await expect(new Cluster(log).run()).rejects.toThrowError(
'ES exited with code 1'
);
});
it('rejects if #start() was called previously', async () => {
mockEsBin({ exitCode: 0, start: true });
const cluster = new Cluster(log);
await cluster.start();
await expect(cluster.run()).rejects.toThrowError(
'ES has already been started'
);
});
it('rejects if #run() was called previously', async () => {
mockEsBin({ exitCode: 0 });
const cluster = new Cluster(log);
await cluster.run();
await expect(cluster.run()).rejects.toThrowError(
'ES has already been started'
);
});
});
describe('#stop()', () => {
it('rejects if #run() or #start() was not called', async () => {
const cluster = new Cluster(log);
await expect(cluster.stop()).rejects.toThrowError(
'ES has not been started'
);
});
it('resolves when ES exits with 0', async () => {
mockEsBin({ exitCode: 0, start: true });
const cluster = new Cluster(log);
await cluster.start();
await cluster.stop();
});
it('resolves when ES exits with 143', async () => {
mockEsBin({ exitCode: 143, start: true });
const cluster = new Cluster(log);
await cluster.start();
await cluster.stop();
});
it('resolves when ES exits with 130', async () => {
mockEsBin({ exitCode: 130, start: true });
const cluster = new Cluster(log);
await cluster.start();
await cluster.stop();
});
it('rejects when ES exits with 1', async () => {
mockEsBin({ exitCode: 1, start: true });
const cluster = new Cluster(log);
await expect(cluster.run()).rejects.toThrowError('ES exited with code 1');
await expect(cluster.stop()).rejects.toThrowError('ES exited with code 1');
});
});