The first version seeded chart_profiles, which the runtime role cannot read directly; the gate failed with permission denied (run 4168). Co-Authored-By: Claude Opus 5.5 (1M context) <noreply@anthropic.com> Claude-Session: https://claude.ai/code/session_014Ad9rqAB8pXXvyzh7f4X8v
70 lines
3.4 KiB
TypeScript
70 lines
3.4 KiB
TypeScript
import assert from "node:assert/strict";
|
|
import { randomUUID } from "node:crypto";
|
|
import { spawnSync } from "node:child_process";
|
|
import { fileURLToPath } from "node:url";
|
|
import test from "node:test";
|
|
|
|
import { closeLocalPostgresDataPool, createLocalPostgresDataClient } from "../src/lib/db/local-postgres-client-core.ts";
|
|
import { startPostgresFixture, type PostgresFixture } from "./helpers/postgres-fixture.ts";
|
|
|
|
// BUG-1399: `.gte()` was missing from the self-hosted client, so the synastry
|
|
// report's "reports created today" count threw before anything was reserved.
|
|
// This runs the same filters against a real database. Fictional rows only.
|
|
const runner = fileURLToPath(new URL("../scripts/db-migrate.mjs", import.meta.url));
|
|
const docker = spawnSync("docker", ["version", "--format", "{{.Server.Version}}"], { stdio: "ignore" }).status === 0;
|
|
const SERVICE_URL_ROLE = ["service_runtime", "service-runtime-test-password"] as const;
|
|
|
|
function applyMigrations(fixture: PostgresFixture): void {
|
|
const result = spawnSync(process.execPath, [runner], {
|
|
encoding: "utf8",
|
|
env: {
|
|
...process.env,
|
|
SCHEMA_DATABASE_URL: fixture.connectionUrl("schema_owner", "schema-owner-test-password"),
|
|
},
|
|
});
|
|
assert.equal(result.status, 0, result.stderr || result.stdout);
|
|
}
|
|
|
|
test("gte and lt filter real rows, and the synastry daily count query runs", {
|
|
skip: docker ? false : "docker unavailable",
|
|
}, async () => {
|
|
const fixture = startPostgresFixture();
|
|
const serviceUrl = fixture.connectionUrl(...SERVICE_URL_ROLE);
|
|
try {
|
|
applyMigrations(fixture);
|
|
const owner = randomUUID();
|
|
// A probe table keeps this a query-builder test: runtime roles have no
|
|
// direct DML on business tables, so grant select on the probe only.
|
|
fixture.psql(`create table public.range_filter_probe (id integer primary key, seen_at timestamptz not null);
|
|
insert into public.range_filter_probe values (1, '2026-10-01T00:00:00Z'), (2, '2026-10-21T08:00:00Z');
|
|
grant select on table public.range_filter_probe to service_role;`);
|
|
|
|
const admin = createLocalPostgresDataClient(serviceUrl, null, "service_role");
|
|
const since = await admin.from("range_filter_probe").select("id")
|
|
.gte("seen_at", "2026-10-21T00:00:00.000Z");
|
|
assert.equal(since.error, null, since.error?.message ?? "gte failed");
|
|
assert.deepEqual((since.data as Array<{ id: number }>).map((row) => row.id), [2]);
|
|
|
|
const before = await admin.from("range_filter_probe").select("id")
|
|
.lt("seen_at", "2026-10-21T00:00:00.000Z");
|
|
assert.equal(before.error, null, before.error?.message ?? "lt failed");
|
|
assert.deepEqual((before.data as Array<{ id: number }>).map((row) => row.id), [1]);
|
|
|
|
const boundary = await admin.from("range_filter_probe").select("id")
|
|
.gte("seen_at", "2026-10-21T08:00:00.000Z")
|
|
.lt("seen_at", "2026-10-21T08:00:00.001Z");
|
|
assert.equal(boundary.error, null, boundary.error?.message ?? "range failed");
|
|
assert.deepEqual((boundary.data as Array<{ id: number }>).map((row) => row.id), [2]);
|
|
|
|
// The exact chain createSynastryFullReport uses for today's count.
|
|
const today = await admin.from("personal_reports").select("created_at")
|
|
.eq("user_id", owner)
|
|
.gte("created_at", "2026-10-21T00:00:00.000Z");
|
|
assert.equal(today.error, null, today.error?.message ?? "personal_reports gte failed");
|
|
assert.deepEqual(today.data, []);
|
|
} finally {
|
|
await closeLocalPostgresDataPool(serviceUrl);
|
|
fixture.stop();
|
|
}
|
|
});
|