Files
Jyotisha/frontend/tests/local-postgres-roundtrips.test.ts
T
jesse-uxandGrok (agent loop) 4c3485bc23 服务器长跑不再堆积取消监听,数据库少走几趟。
报告工人的等待到点就摘掉取消监听。本地数据库缓存表结构,并把设置身份合成一条语句,对照通过后默认打开,写成 off 仍走原来的语句。交付、重算和限流的内存表会过期。登录读缓存默认关闭,要开再设 IDENTITY_SESSION_COOKIE_CACHE=on。

自测:tsc 通过,lint 0 error,点名测试 134 通过,test:db 开关关和开都只有已知的 13 条失败,往返 49 降到 32。

Co-Authored-By: Grok (agent loop)
2026-10-14 03:32:39 +08:00

287 lines
10 KiB
TypeScript

import assert from "node:assert/strict";
import test from "node:test";
import type { Pool } from "pg";
import {
clearLocalPostgresMetadataCacheForTests,
closeLocalPostgresDataPool,
createLocalPostgresDataClient,
installLocalPostgresPoolForTests,
setLocalPostgresMetadataClockForTests,
type LocalDatabaseRole,
} from "../src/lib/db/local-postgres-client-core.ts";
type QueryCall = { sql: string; params: readonly unknown[] };
function tag(sql: string): string {
const compact = sql.replace(/\s+/g, " ").trim().toLowerCase();
if (compact === "begin") return "begin";
if (compact === "commit") return "commit";
if (compact === "rollback") return "rollback";
if (compact.startsWith("set local role")) return "set local role";
if (compact.includes("set_config('role'")) return "set_config(role)";
if (compact.includes("set_config('request.jwt.claim.sub'")) return "set_config";
if (compact.includes("information_schema.columns")) return "information_schema";
if (compact.includes("from pg_index")) return "primary_key";
if (compact.includes("from pg_proc")) return "pg_proc";
return "business";
}
function installFakePool(
url: string,
options: {
columns?: ReadonlyArray<{ column_name: string; udt_name: string }> | null;
primaryKeys?: readonly string[] | null;
functions?: ReadonlyArray<Record<string, unknown>> | null;
failBusinessCode?: () => string | null;
} = {},
): QueryCall[] {
const calls: QueryCall[] = [];
const client = {
async query(sql: string, params: readonly unknown[] = []) {
calls.push({ sql, params });
const label = tag(sql);
if (label === "information_schema") {
const rows = options.columns === null
? []
: [...(options.columns ?? [{ column_name: "id", udt_name: "uuid" }])];
return { rows, rowCount: rows.length };
}
if (label === "primary_key") {
const names = options.primaryKeys === null ? [] : [...(options.primaryKeys ?? ["id"])];
const rows = names.map((column_name) => ({ column_name }));
return { rows, rowCount: rows.length };
}
if (label === "pg_proc") {
const rows = options.functions === null
? []
: [...(options.functions ?? [{
proretset: false,
return_type: "text",
argument_names: ["left_name", "right_name"],
argument_types: ["text", "text"],
}])];
return { rows, rowCount: rows.length };
}
if (label === "business") {
const code = options.failBusinessCode?.() ?? null;
if (code) {
const error = new Error("business sql failed") as Error & { code: string };
error.code = code;
throw error;
}
if (sql.toLowerCase().includes(" as value")) return { rows: [{ value: "ok" }], rowCount: 1 };
}
return { rows: [], rowCount: 0 };
},
release() {},
};
const pool = {
async connect() {
return client;
},
async end() {},
};
installLocalPostgresPoolForTests(url, pool as unknown as Pool);
return calls;
}
async function withSwitches(
values: Record<string, string | undefined>,
run: () => Promise<void>,
): Promise<void> {
const previous = new Map<string, string | undefined>();
for (const [key, value] of Object.entries(values)) {
previous.set(key, process.env[key]);
if (value === undefined) delete process.env[key];
else process.env[key] = value;
}
clearLocalPostgresMetadataCacheForTests();
setLocalPostgresMetadataClockForTests(null);
try {
await run();
} finally {
for (const [key, value] of previous) {
if (value === undefined) delete process.env[key];
else process.env[key] = value;
}
clearLocalPostgresMetadataCacheForTests();
setLocalPostgresMetadataClockForTests(null);
}
}
const identity = { id: "018f4e6d-7a11-7000-8000-0000000000aa", email: "person@example.com" };
function clientFor(url: string, role: LocalDatabaseRole | null = "authenticated") {
return createLocalPostgresDataClient(url, role === "service_role" ? null : identity, role);
}
test("metadata cache and merged session setup stay off the baseline query sequence", async () => {
await withSwitches({
JYOTISHA_PG_METADATA_CACHE: "off",
JYOTISHA_PG_MERGED_SESSION_SETUP: "off",
}, async () => {
const url = "postgresql://roundtrip-off@127.0.0.1:1/jyotisha";
const calls = installFakePool(url);
const client = clientFor(url);
const first = await client.from("profiles").select("id").eq("id", identity.id);
assert.equal(first.error, null);
assert.deepEqual(calls.map((call) => tag(call.sql)), [
"begin",
"set local role",
"set_config",
"information_schema",
"business",
"commit",
]);
await client.from("profiles").select("id").eq("id", identity.id);
assert.equal(calls.filter((call) => tag(call.sql) === "information_schema").length, 2);
});
});
test("cached metadata and merged session setup drop a repeat select and rpc to four roundtrips", async () => {
await withSwitches({
JYOTISHA_PG_METADATA_CACHE: "on",
JYOTISHA_PG_MERGED_SESSION_SETUP: "on",
}, async () => {
const url = "postgresql://roundtrip-on@127.0.0.1:1/jyotisha";
const calls = installFakePool(url);
const client = clientFor(url);
await client.from("profiles").select("id").eq("id", identity.id);
calls.length = 0;
await client.from("profiles").select("id").eq("id", identity.id);
assert.deepEqual(calls.map((call) => tag(call.sql)), [
"begin",
"set_config(role)",
"business",
"commit",
]);
await client.rpc("sample_probe", { left_name: "a", right_name: "b" });
calls.length = 0;
const rpc = await client.rpc("sample_probe", { left_name: "a", right_name: "b" });
assert.equal(rpc.error, null);
assert.deepEqual(calls.map((call) => tag(call.sql)), [
"begin",
"set_config(role)",
"business",
"commit",
]);
await client.from("profiles").upsert({ id: identity.id });
calls.length = 0;
await client.from("profiles").upsert({ id: identity.id });
assert.deepEqual(calls.map((call) => tag(call.sql)), [
"begin",
"set_config(role)",
"business",
"commit",
]);
});
});
test("column cache is per role and function cache is per argument names", async () => {
await withSwitches({
JYOTISHA_PG_METADATA_CACHE: "on",
JYOTISHA_PG_MERGED_SESSION_SETUP: "on",
}, async () => {
const url = "postgresql://roundtrip-keys@127.0.0.1:1/jyotisha";
const calls = installFakePool(url);
const authenticated = clientFor(url, "authenticated");
const service = clientFor(url, "service_role");
await authenticated.from("profiles").select("id");
calls.length = 0;
await service.from("profiles").select("id");
assert.equal(calls.filter((call) => tag(call.sql) === "information_schema").length, 1);
await authenticated.rpc("sample_probe", { left_name: "a" });
calls.length = 0;
await authenticated.rpc("sample_probe", { right_name: "b" });
assert.equal(calls.filter((call) => tag(call.sql) === "pg_proc").length, 1);
});
});
test("undefined column, expiry, pool close, and empty metadata all miss the cache", async () => {
await withSwitches({
JYOTISHA_PG_METADATA_CACHE: "on",
JYOTISHA_PG_MERGED_SESSION_SETUP: "off",
}, async () => {
const url = "postgresql://roundtrip-invalidate@127.0.0.1:1/jyotisha";
let failuresLeft = 1;
const calls = installFakePool(url, {
failBusinessCode: () => {
if (failuresLeft <= 0) return null;
failuresLeft -= 1;
return "42703";
},
});
const client = clientFor(url);
const failed = await client.from("profiles").select("id");
assert.equal(failed.error?.code, "42703");
calls.length = 0;
const retried = await client.from("profiles").select("id");
assert.equal(retried.error, null);
assert.equal(calls.filter((call) => tag(call.sql) === "information_schema").length, 1);
});
});
test("metadata older than 300 seconds is queried again", async () => {
await withSwitches({
JYOTISHA_PG_METADATA_CACHE: "on",
JYOTISHA_PG_MERGED_SESSION_SETUP: "off",
}, async () => {
const url = "postgresql://roundtrip-ttl@127.0.0.1:1/jyotisha";
let now = 10_000;
setLocalPostgresMetadataClockForTests(() => now);
const calls = installFakePool(url);
const client = clientFor(url);
await client.from("profiles").select("id");
calls.length = 0;
await client.from("profiles").select("id");
assert.equal(calls.filter((call) => tag(call.sql) === "information_schema").length, 0);
now += 300_000;
calls.length = 0;
await client.from("profiles").select("id");
assert.equal(calls.filter((call) => tag(call.sql) === "information_schema").length, 1);
});
});
test("an empty column list and a missing function are not cached", async () => {
await withSwitches({
JYOTISHA_PG_METADATA_CACHE: "on",
JYOTISHA_PG_MERGED_SESSION_SETUP: "off",
}, async () => {
const url = "postgresql://roundtrip-empty@127.0.0.1:1/jyotisha";
const calls = installFakePool(url, { columns: null, functions: null, primaryKeys: null });
const client = clientFor(url);
await client.from("profiles").select("id");
calls.length = 0;
await client.from("profiles").select("id");
assert.equal(calls.filter((call) => tag(call.sql) === "information_schema").length, 1);
const missing = await client.rpc("missing_probe", { left_name: "a" });
assert.match(missing.error?.message ?? "", /not found/);
calls.length = 0;
await client.rpc("missing_probe", { left_name: "a" });
assert.equal(calls.filter((call) => tag(call.sql) === "pg_proc").length, 1);
});
});
test("closing the pool drops that url from the metadata cache", async () => {
await withSwitches({
JYOTISHA_PG_METADATA_CACHE: "on",
JYOTISHA_PG_MERGED_SESSION_SETUP: "off",
}, async () => {
const url = "postgresql://roundtrip-close@127.0.0.1:1/jyotisha";
const calls = installFakePool(url);
const client = clientFor(url);
await client.from("profiles").select("id");
await closeLocalPostgresDataPool(url);
const reopenedCalls = installFakePool(url);
const reopened = clientFor(url);
await reopened.from("profiles").select("id");
assert.equal(reopenedCalls.filter((call) => tag(call.sql) === "information_schema").length, 1);
assert.ok(calls.length > 0);
});
});