2023-11-30 19:08:46 +00:00
|
|
|
import {prepareDatabase} from 'test/server/lib/helpers/PrepareDatabase';
|
|
|
|
import {TestServer} from 'test/server/lib/helpers/TestServer';
|
|
|
|
import {createTestDir, setTmpLogLevel} from 'test/server/testUtils';
|
2023-12-27 14:56:59 +00:00
|
|
|
import * as testUtils from 'test/server/testUtils';
|
2023-11-30 19:08:46 +00:00
|
|
|
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;
|
2023-12-27 14:56:59 +00:00
|
|
|
let oldEnv: testUtils.EnvironmentSnapshot;
|
2023-11-30 19:08:46 +00:00
|
|
|
|
|
|
|
before(async function() {
|
2023-12-27 14:56:59 +00:00
|
|
|
oldEnv = new testUtils.EnvironmentSnapshot();
|
2023-11-30 19:08:46 +00:00
|
|
|
testDir = await createTestDir('UnhandledErrors');
|
|
|
|
await prepareDatabase(testDir);
|
|
|
|
});
|
|
|
|
|
2023-12-27 14:56:59 +00:00
|
|
|
after(function() {
|
|
|
|
oldEnv.restore();
|
|
|
|
});
|
|
|
|
|
2023-11-30 19:08:46 +00:00
|
|
|
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();
|
|
|
|
}
|
|
|
|
});
|
|
|
|
}
|
|
|
|
});
|