Files
openswarm/electron/crashReports.test.js

80 lines
3.1 KiB
JavaScript

// Run: node --test electron/crashReports.test.js
//
// ENG-265 / ENG-285. Four real renderer crashes were fired at the packaged app and NO crash report
// appeared, with no error line either. That left three indistinguishable explanations: the handler
// never ran, dedupe suppressed it, or the session cap was hit. `writeCrashReport` returned a bare
// null on two of those paths and said nothing, so the instrumentation built to diagnose a crash was
// itself undiagnosable.
//
// These assert that a decline is always ANNOUNCED. A crash handler that silently declines is worse
// than one that fails loudly, because the silence is read as "no crash happened".
const test = require('node:test');
const assert = require('node:assert/strict');
const path = require('path');
const os = require('os');
const fs = require('fs');
const crash = require('./crashReports.js');
function withCapturedWarn(fn) {
const lines = [];
const original = console.warn;
console.warn = (...a) => lines.push(a.join(' '));
try { fn(); } finally { console.warn = original; }
return lines;
}
function initInTemp() {
const dir = fs.mkdtempSync(path.join(os.tmpdir(), 'osw-crash-'));
crash.init({
getVersion: () => '0.0.0-test',
getPath: () => dir,
}, null);
return dir;
}
test('a deduped report says so instead of returning silently', () => {
initInTemp();
const first = crash.writeCrashReport('renderer-gone', { message: 'crashed' });
assert.ok(first, 'the first report should be written');
const lines = withCapturedWarn(() => {
const second = crash.writeCrashReport('renderer-gone', { message: 'crashed' });
assert.equal(second, null, 'an identical crash inside the window must still be suppressed');
});
assert.ok(
lines.some((l) => l.includes('declined') && l.includes('deduped')),
`a suppressed report announced nothing; lines were ${JSON.stringify(lines)}`,
);
});
test('the announcement carries the fingerprint and the repeat count, not just a word', () => {
initInTemp();
crash.writeCrashReport('gpu-gone', { message: 'oom' });
const lines = withCapturedWarn(() => crash.writeCrashReport('gpu-gone', { message: 'oom' }));
assert.ok(lines.some((l) => /seen \d+x/.test(l)), `no repeat count in ${JSON.stringify(lines)}`);
});
test('a DIFFERENT crash is not deduped, so the guard cannot swallow real reports', () => {
initInTemp();
assert.ok(crash.writeCrashReport('renderer-gone', { message: 'crashed' }));
assert.ok(
crash.writeCrashReport('renderer-gone', { message: 'oom' }),
'a different fingerprint was suppressed; the dedupe is too broad',
);
});
test('the session cap announces itself rather than going quiet', () => {
initInTemp();
for (let i = 0; i < crash.MAX_REPORTS_PER_SESSION; i++) {
crash.writeCrashReport('renderer-gone', { message: `distinct-${i}` });
}
const lines = withCapturedWarn(() => {
const over = crash.writeCrashReport('renderer-gone', { message: 'one-too-many' });
assert.equal(over, null, 'the cap must still hold');
});
assert.ok(
lines.some((l) => l.includes('declined') && l.includes('capped')),
`hitting the cap announced nothing; lines were ${JSON.stringify(lines)}`,
);
});