-
Notifications
You must be signed in to change notification settings - Fork 8.3k
Commit
This commit does not belong to any branch on this repository, and may belong to a fork outside of the repository.
[kbn-es] add basic integration tests for exit code/promise handling (#…
- Loading branch information
Showing
3 changed files
with
340 additions
and
1 deletion.
There are no files selected for viewing
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,9 @@ | ||
#!/usr/bin/env node | ||
|
||
const { exitCode, start } = JSON.parse(process.argv[2]); | ||
|
||
if (start) { | ||
console.log('started'); | ||
} | ||
|
||
process.exitCode = exitCode; |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -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'); | ||
}); | ||
}); |