feat: add extensive test suite

This commit is contained in:
2026-08-30 11:33:53 +07:00 Unverified
parent 061cce00dc
commit 8359c7272e
131 changed files with 8717 additions and 2200 deletions
+58
View File
@@ -0,0 +1,58 @@
type DebugRuntime = {
bun: string;
node: string;
platform: string;
arch: string;
uptime: number;
};
type DebugHandlerDependencies = {
adminCheck: () => Promise<unknown>;
runtime: () => DebugRuntime;
memoryUsage: () => NodeJS.MemoryUsage;
probes: ReadonlyArray<{
name: string;
run: () => Promise<unknown>;
}>;
now?: () => number;
};
export function createDebugHandler({
adminCheck,
runtime,
memoryUsage,
probes,
now = () => performance.now(),
}: DebugHandlerDependencies) {
return async function getDebugStatus() {
try {
if (!(await adminCheck())) return unauthorized();
} catch {
return unauthorized();
}
const results = await Promise.all(
probes.map(async ({ name, run }) => {
const started = now();
try {
await run();
return { name, ok: true, latencyMs: now() - started };
} catch {
return { name, ok: false, latencyMs: now() - started };
}
}),
);
return Response.json({
timestamp: new Date().toISOString(),
runtime: runtime(),
memory: memoryUsage(),
probes: results,
});
};
}
function unauthorized() {
return new Response("Unauthorized", { status: 401 });
}
+109
View File
@@ -0,0 +1,109 @@
import { describe, expect, mock, test } from "bun:test";
import { createDebugHandler } from "./handler";
const runtime = () => ({
bun: "1.0.0",
node: "v20.0.0",
platform: "linux",
arch: "x64",
uptime: 10,
});
const memoryUsage = () => ({
rss: 1,
heapTotal: 2,
heapUsed: 3,
external: 4,
arrayBuffers: 5,
});
describe("debug route handler", () => {
test("rejects non-admin requests without running probes", async () => {
const run = mock(async () => "PONG");
const handler = createDebugHandler({
adminCheck: mock(async () => null),
runtime,
memoryUsage,
probes: [{ name: "redis", run }],
});
const response = await handler();
expect(response.status).toBe(401);
expect(await response.text()).toBe("Unauthorized");
expect(run).not.toHaveBeenCalled();
});
test("fails closed when admin authentication throws", async () => {
const run = mock(async () => "PONG");
const handler = createDebugHandler({
adminCheck: mock(async () => {
throw new Error("session database unavailable");
}),
runtime,
memoryUsage,
probes: [{ name: "redis", run }],
});
const response = await handler();
expect(response.status).toBe(401);
expect(run).not.toHaveBeenCalled();
});
test("returns bounded diagnostics to an admin", async () => {
let time = 10;
const handler = createDebugHandler({
adminCheck: mock(async () => ({ role: "admin" })),
runtime,
memoryUsage,
probes: [
{ name: "redis", run: mock(async () => "PONG") },
{
name: "postgres",
run: mock(async () => {
throw new Error("password=secret\nstack trace");
}),
},
],
now: () => time++,
});
const response = await handler();
const body = await response.json();
const serialized = JSON.stringify(body);
expect(response.status).toBe(200);
expect(body).toMatchObject({
runtime: runtime(),
memory: memoryUsage(),
probes: [
{ name: "redis", ok: true },
{ name: "postgres", ok: false },
],
});
expect(
body.probes.every(
({ latencyMs }: { latencyMs: number }) => latencyMs >= 0,
),
).toBeTrue();
expect(serialized).not.toContain("secret");
expect(serialized).not.toContain("stack");
expect(serialized).not.toContain("cookie");
expect(serialized).not.toContain("authorization");
expect(body).not.toHaveProperty("env");
expect(body).not.toHaveProperty("request");
});
test("uses the runtime performance clock by default", async () => {
const handler = createDebugHandler({
adminCheck: mock(async () => ({ role: "admin" })),
runtime,
memoryUsage,
probes: [{ name: "redis", run: mock(async () => "PONG") }],
});
const body = await (await handler()).json();
expect(body.probes[0].latencyMs).toBeGreaterThanOrEqual(0);
});
});
+35 -112
View File
@@ -1,126 +1,49 @@
import { sql } from "drizzle-orm";
import { youtubeCache } from "@/lib/adaptive-cache";
import { adminCheck } from "@/lib/auth";
import { db } from "@/lib/db";
import { redis } from "@/lib/db/redis";
import { env } from "bun";
import { sql } from "drizzle-orm";
import type { NextRequest } from "next/server";
import { createDebugHandler } from "./handler";
async function probe(name: string, fn: () => Promise<unknown>) {
const started = performance.now();
const timeoutMs = 5_000;
try {
const result = await fn();
return {
name,
ok: true,
latencyMs: performance.now() - started,
result,
};
} catch (error) {
return {
name,
ok: false,
latencyMs: performance.now() - started,
error:
error instanceof Error
? {
name: error.name,
message: error.message,
stack: error.stack,
cause: error.cause,
}
: error,
};
}
}
export async function GET(request: NextRequest) {
try {
if (!(await adminCheck())) {
return new Response("Unauthorized", { status: 401 });
}
} catch {
// idiomatic fallback
// even though this is extremely risky, we need it
console.error("/api/debug AUTH CHECK ERROR");
// use REDIS_URL which only I can memorize as the password,
// or IF THAT fails too, use a static string, which shouldn't ever happen
if (
request.nextUrl.searchParams.get("pass") !==
(env.REDIS_URL || "absolute_solver")
)
return new Response("Unauthorized (Fallback)", { status: 401 });
}
const probes = await Promise.all([
probe("redis", async () => {
const started = performance.now();
const result = await withTimeout(redis!.ping(), 5000);
return {
result,
latencyMs: performance.now() - started,
};
}),
probe("postgres", async () => {
const started = performance.now();
const result = await withTimeout(db.execute(sql`SELECT 1`), 5000);
return {
result,
latencyMs: performance.now() - started,
};
}),
]);
return Response.json({
timestamp: new Date().toISOString(),
runtime: safe({
bun: Bun.version,
node: process.version,
platform: process.platform,
arch: process.arch,
pid: process.pid,
uptime: process.uptime(),
cwd: process.cwd(),
}),
memory: process.memoryUsage(),
eventLoop: {
now: performance.now(),
export const GET = createDebugHandler({
adminCheck,
runtime: () => ({
bun: Bun.version,
node: process.version,
platform: process.platform,
arch: process.arch,
uptime: process.uptime(),
}),
memoryUsage: () => process.memoryUsage(),
probes: [
{
name: "redis",
run: () => withTimeout(redis!.ping(), timeoutMs),
},
request: {
url: request.url,
headers: safe(Object.fromEntries(request.headers)),
{
name: "postgres",
run: () => withTimeout(db.execute(sql`SELECT 1`), timeoutMs),
},
ytCache: await probe("youtubeCache", async () => youtubeCache.debugStats()),
env,
probes,
});
}
{
name: "youtubeCache",
run: () => withTimeout(youtubeCache.debugStats(), timeoutMs),
},
],
});
async function withTimeout<T>(promise: Promise<T>, ms: number): Promise<T> {
return Promise.race([
promise,
new Promise<T>((_, reject) =>
setTimeout(() => reject(new Error(`Timeout after ${ms}ms`)), ms),
),
]);
}
let timeout: ReturnType<typeof setTimeout>;
function safe(value: unknown) {
try {
return JSON.parse(JSON.stringify(value));
} catch {
return String(value);
return await Promise.race([
promise,
new Promise<T>((_, reject) => {
timeout = setTimeout(() => reject(new Error("Probe timed out")), ms);
}),
]);
} finally {
clearTimeout(timeout!);
}
}