mirror of
https://github.com/diegosouzapw/OmniRoute.git
synced 2026-07-26 09:52:11 +03:00
116 lines
4.1 KiB
TypeScript
116 lines
4.1 KiB
TypeScript
import { test } from "node:test";
|
|
import assert from "node:assert/strict";
|
|
import { ensureDbReadyForBoot } from "../../src/instrumentation-node";
|
|
|
|
// Regression guard for #7773: on Termux/Android, when the whole SQLite driver
|
|
// cascade (better-sqlite3 -> node:sqlite -> sql.js) fails at boot,
|
|
// ensureDbReadyForBoot() used to re-throw the fatal error WITHOUT ever
|
|
// logging it, and this happens before initConsoleInterceptor() runs — so the
|
|
// one message that would explain the crash never reached app.log. The server
|
|
// kept listening (hence "OmniRoute is running") but every DB-touching route
|
|
// 500s forever with a permanently empty log.
|
|
|
|
function captureConsole(): { captured: string[]; restore: () => void } {
|
|
const originalError = console.error;
|
|
const originalWarn = console.warn;
|
|
const originalLog = console.log;
|
|
const captured: string[] = [];
|
|
const join = (args: unknown[]): string => args.map((arg) => String(arg)).join(" ");
|
|
console.error = (...args: unknown[]) => {
|
|
captured.push(join(args));
|
|
};
|
|
console.warn = (...args: unknown[]) => {
|
|
captured.push(join(args));
|
|
};
|
|
console.log = (...args: unknown[]) => {
|
|
captured.push(join(args));
|
|
};
|
|
return {
|
|
captured,
|
|
restore: () => {
|
|
console.error = originalError;
|
|
console.warn = originalWarn;
|
|
console.log = originalLog;
|
|
},
|
|
};
|
|
}
|
|
|
|
test("issue #7773: a fatal (non-transient) boot-time DB init failure must be logged before it propagates", async () => {
|
|
const { captured, restore } = captureConsole();
|
|
|
|
// Mirrors the real message driverFactory.ts's openSqliteDatabase() throws once
|
|
// better-sqlite3 + node:sqlite are both unavailable AND sql.js pre-init itself
|
|
// failed (core.ts:172-176) — the exact shape a Termux install with no working
|
|
// SQLite driver at all would surface.
|
|
const fatalMessage =
|
|
"[DB] Nenhum driver SQLite disponível para '/data/data/com.termux/files/home/.omniroute/storage.sqlite'. " +
|
|
"Drivers testados: better-sqlite3 (falhou), node:sqlite (indisponível), " +
|
|
"sql.js (falhou: ENOENT: no such file or directory, open '.../sql-wasm.wasm').";
|
|
|
|
const fakeEnsureDbInitialized = async () => {
|
|
throw new Error(fatalMessage);
|
|
};
|
|
|
|
try {
|
|
await assert.rejects(
|
|
() => ensureDbReadyForBoot(fakeEnsureDbInitialized),
|
|
(err: Error) => err.message === fatalMessage
|
|
);
|
|
|
|
const loggedRootCause = captured.some((line) => line.includes(fatalMessage));
|
|
assert.equal(
|
|
loggedRootCause,
|
|
true,
|
|
"Expected the fatal boot-time DB init failure to be logged (console.error/warn) " +
|
|
"before propagating, so app.log captures the real driver-cascade failure reason " +
|
|
"instead of staying empty (#7773). It was NOT logged."
|
|
);
|
|
} finally {
|
|
restore();
|
|
}
|
|
});
|
|
|
|
test("issue #7773: a fatal failure on the retry-after-#6560 path must also be logged before it propagates", async () => {
|
|
const { captured, restore } = captureConsole();
|
|
|
|
const fatalMessage = "[DB] sql.js pre-init failed: WASM asset missing on retry";
|
|
let calls = 0;
|
|
const fakeEnsureDbInitialized = async () => {
|
|
calls += 1;
|
|
if (calls === 1) {
|
|
// Triggers the existing #6560 transient-retry branch first.
|
|
throw "Database closed";
|
|
}
|
|
throw new Error(fatalMessage);
|
|
};
|
|
|
|
try {
|
|
await assert.rejects(
|
|
() => ensureDbReadyForBoot(fakeEnsureDbInitialized),
|
|
(err: Error) => err.message === fatalMessage
|
|
);
|
|
assert.equal(calls, 2, "must have retried exactly once before the fatal retry failure");
|
|
|
|
const loggedRootCause = captured.some((line) => line.includes(fatalMessage));
|
|
assert.equal(
|
|
loggedRootCause,
|
|
true,
|
|
"Expected the fatal retry-path DB init failure to also be logged before propagating (#7773)."
|
|
);
|
|
} finally {
|
|
restore();
|
|
}
|
|
});
|
|
|
|
test("ensureDbReadyForBoot does not log anything extra on a clean successful boot", async () => {
|
|
const { captured, restore } = captureConsole();
|
|
const fakeEnsureDbInitialized = async () => {};
|
|
|
|
try {
|
|
await assert.doesNotReject(ensureDbReadyForBoot(fakeEnsureDbInitialized));
|
|
assert.equal(captured.length, 0, "a successful boot must not emit any startup DB log lines");
|
|
} finally {
|
|
restore();
|
|
}
|
|
});
|