gristlabs_grist-core/test/server/lib/UnhandledErrors.ts

55 lines
2.0 KiB
TypeScript
Raw Normal View History

import {prepareDatabase} from 'test/server/lib/helpers/PrepareDatabase';
import {TestServer} from 'test/server/lib/helpers/TestServer';
import {createTestDir, setTmpLogLevel} from 'test/server/testUtils';
import {waitForIt} from 'test/server/wait';
import {assert} from 'chai';
import fetch from 'node-fetch';
import {PassThrough} from 'stream';
/**
* Grist sticks to the Node 18 default and recommendation to give up and exit on uncaught
* exceptions, unhandled promise rejections, and unhandled 'error' events. But it makes an effort
* to clean up before exiting, and to log the error in a better way.
*/
describe('UnhandledErrors', function() {
this.timeout(30000);
setTmpLogLevel('warn');
let testDir: string;
before(async function() {
testDir = await createTestDir('UnhandledErrors');
await prepareDatabase(testDir);
});
for (const errType of ['exception', 'rejection', 'error-event']) {
it(`should clean up on unhandled ${errType}`, async function() {
// Capture server log output, so that we can look to see how the server coped.
const output = new PassThrough();
const serverLogLines: string[] = [];
output.on('data', (data) => serverLogLines.push(data.toString()));
const server = await TestServer.startServer('home', testDir, errType, undefined, undefined, {output});
try {
assert.equal((await fetch(`${server.serverUrl}/status`)).status, 200);
serverLogLines.length = 0;
// Trigger an unhandled error, and check that the server logged it and attempted cleanup.
await server.testingHooks.tickleUnhandledErrors(errType);
await waitForIt(() => {
assert.isTrue(serverLogLines.some(line => new RegExp(`Fake ${errType}`).test(line)));
assert.isTrue(serverLogLines.some(line => /Server .* cleaning up/.test(line)));
}, 1000, 100);
// We expect the server to be dead now.
await assert.isRejected(fetch(`${server.serverUrl}/status`), /failed.*ECONNREFUSED/);
} finally {
await server.stop();
}
});
}
});