182 lines
7.8 KiB
TypeScript
182 lines
7.8 KiB
TypeScript
import assert from "node:assert/strict";
|
|
import { spawnSync } from "node:child_process";
|
|
import test from "node:test";
|
|
import { startPostgresFixture } from "./helpers/postgres-fixture.ts";
|
|
import { readFileSync } from "node:fs";
|
|
import { assembleReportFactTables } from "../src/lib/report-fact-tables";
|
|
import { assembleLongformCharts } from "../src/lib/personal-report-generation";
|
|
import { hashLongformMarkdown } from "../src/lib/personal-report-longform-appendix";
|
|
import { LONGFORM_SNAPSHOT_SECTION_ID, validateLongformSnapshot } from "../src/lib/personal-report-longform-snapshot";
|
|
|
|
const runnerPath = new URL("../scripts/db-migrate.mjs", import.meta.url).pathname;
|
|
const USER_A = "aaaaaaaa-aaaa-4aaa-8aaa-aaaaaaaaaaaa";
|
|
const USER_B = "bbbbbbbb-bbbb-4bbb-8bbb-bbbbbbbbbbbb";
|
|
const REPORT_ID = "cccccccc-cccc-4ccc-8ccc-cccccccccccc";
|
|
const REQUEST_ID = "dddddddd-dddd-4ddd-8ddd-dddddddddddd";
|
|
const SECTION_ID = "theme-career";
|
|
|
|
function selectAsAuthenticated(userId: string, sql: string): string {
|
|
return `
|
|
set role authenticated;
|
|
select set_config('request.jwt.claim.sub', '${userId}', true);
|
|
${sql}
|
|
`;
|
|
}
|
|
|
|
function serviceSql(sql: string): string {
|
|
return `set role service_role;\n${sql}`;
|
|
}
|
|
|
|
test("personal report sections enforce owner-read RLS and service-owned durable transitions", () => {
|
|
const fixture = startPostgresFixture();
|
|
const schemaUrl = fixture.connectionUrl("schema_owner", "schema-owner-test-password");
|
|
|
|
try {
|
|
const migration = spawnSync(process.execPath, [runnerPath], {
|
|
encoding: "utf8",
|
|
env: { ...process.env, SCHEMA_DATABASE_URL: schemaUrl },
|
|
});
|
|
assert.equal(migration.status, 0, migration.stderr);
|
|
assert.match(migration.stdout, /applied 20260830020000_personal_report_sections\.sql/);
|
|
|
|
fixture.psql(`
|
|
insert into identity.users (id, name, email, email_verified, email_verified_at)
|
|
values
|
|
('${USER_A}', 'Section User A', 'section-a@example.com', true, now()),
|
|
('${USER_B}', 'Section User B', 'section-b@example.com', true, now());
|
|
insert into public.personal_reports (
|
|
id, user_id, request_id, request_fingerprint, report_type, status,
|
|
schema_version, presentation_mode, requested_themes, depth,
|
|
skill_name, skill_version, skill_source_commit, skill_snapshot_sha256
|
|
) values (
|
|
'${REPORT_ID}', '${USER_A}', '${REQUEST_ID}', '1111111111111111111111111111111111111111111111111111111111111111', 'personal_full', 'generating',
|
|
'report_document.v2', 'default', array['career']::text[], 'standard',
|
|
'jyotish-personal-report', '1.0.0', '2222222222222222222222222222222222222222', '3333333333333333333333333333333333333333333333333333333333333333'
|
|
);
|
|
`);
|
|
|
|
const own = fixture.psqlAs(
|
|
"app_runtime",
|
|
"app-runtime-test-password",
|
|
selectAsAuthenticated(USER_A, `
|
|
select count(*) from public.personal_report_sections
|
|
where user_id = '${USER_A}' and request_id = '${REQUEST_ID}'
|
|
`),
|
|
);
|
|
assert.equal(own, `SET\n${USER_A}\n0`);
|
|
|
|
fixture.psqlAs(
|
|
"service_runtime",
|
|
"service-runtime-test-password",
|
|
serviceSql(`
|
|
select status from public.ensure_personal_report_section(
|
|
'${USER_A}', '${REQUEST_ID}', '${SECTION_ID}', 2
|
|
);
|
|
select status from public.ensure_personal_report_section(
|
|
'${USER_A}', '${REQUEST_ID}', '${SECTION_ID}', 2
|
|
);
|
|
`),
|
|
);
|
|
|
|
assert.equal(
|
|
fixture.psql(`
|
|
select count(*) from public.personal_report_sections
|
|
where user_id = '${USER_A}' and request_id = '${REQUEST_ID}' and section_id = '${SECTION_ID}'
|
|
`),
|
|
"1",
|
|
);
|
|
|
|
assert.equal(
|
|
fixture.psqlAs(
|
|
"app_runtime",
|
|
"app-runtime-test-password",
|
|
selectAsAuthenticated(USER_A, `
|
|
select status || ':' || attempt_count from public.personal_report_sections
|
|
where user_id = '${USER_A}' and request_id = '${REQUEST_ID}' and section_id = '${SECTION_ID}'
|
|
`),
|
|
),
|
|
`SET\n${USER_A}\npending:0`,
|
|
);
|
|
assert.equal(
|
|
fixture.psqlAs(
|
|
"app_runtime",
|
|
"app-runtime-test-password",
|
|
selectAsAuthenticated(USER_B, `
|
|
select count(*) from public.personal_report_sections
|
|
where user_id = '${USER_A}' and request_id = '${REQUEST_ID}'
|
|
`),
|
|
),
|
|
`SET\n${USER_B}\n0`,
|
|
);
|
|
|
|
assert.throws(
|
|
() => fixture.psqlAs(
|
|
"app_runtime",
|
|
"app-runtime-test-password",
|
|
selectAsAuthenticated(USER_A, `
|
|
insert into public.personal_report_sections (user_id, request_id, section_id)
|
|
values ('${USER_A}', '${REQUEST_ID}', 'theme-wealth');
|
|
`),
|
|
),
|
|
/permission denied for table personal_report_sections/,
|
|
);
|
|
|
|
assert.equal(
|
|
fixture.psqlAs(
|
|
"service_runtime",
|
|
"service-runtime-test-password",
|
|
serviceSql(`
|
|
select status || ':' || attempt_count
|
|
from public.start_personal_report_section('${USER_A}', '${REQUEST_ID}', '${SECTION_ID}');
|
|
`),
|
|
),
|
|
"SET\npending:1",
|
|
);
|
|
assert.equal(
|
|
fixture.psqlAs(
|
|
"service_runtime",
|
|
"service-runtime-test-password",
|
|
serviceSql(`
|
|
select status || ':' || attempt_count
|
|
from public.complete_personal_report_section(
|
|
'${USER_A}', '${REQUEST_ID}', '${SECTION_ID}', '{"title":"事业"}'::jsonb
|
|
);
|
|
`),
|
|
),
|
|
"SET\nready:1",
|
|
);
|
|
assert.equal(
|
|
fixture.psqlAs(
|
|
"service_runtime",
|
|
"service-runtime-test-password",
|
|
serviceSql(`
|
|
select count(*) from public.start_personal_report_section('${USER_A}', '${REQUEST_ID}', '${SECTION_ID}');
|
|
`),
|
|
),
|
|
"SET\n0",
|
|
);
|
|
const packet = JSON.parse(readFileSync(new URL("./fixtures/report-density-fictional-engine.json", import.meta.url), "utf8"));
|
|
const reader = JSON.parse(readFileSync(new URL("./fixtures/report-density-fictional-reader.json", import.meta.url), "utf8"));
|
|
const identity = { reportId: REPORT_ID, userId: USER_A, requestId: REQUEST_ID };
|
|
const snapshot = validateLongformSnapshot({
|
|
...identity, kind: "longform_calculation_snapshot", version: 1,
|
|
markdown: reader.markdown, contentSha256: hashLongformMarkdown(reader.markdown),
|
|
factTables: assembleReportFactTables(packet), charts: assembleLongformCharts(packet, "ev-cover-longform"),
|
|
readerDashaApplicability: reader.reader_dasha_applicability,
|
|
}, identity);
|
|
const encoded = JSON.stringify(snapshot).replaceAll("'", "''");
|
|
fixture.psqlScriptAs("service_runtime", "service-runtime-test-password", serviceSql(`
|
|
select status from public.ensure_personal_report_section('${USER_A}', '${REQUEST_ID}', '${LONGFORM_SNAPSHOT_SECTION_ID}', 2);
|
|
select status from public.complete_personal_report_section('${USER_A}', '${REQUEST_ID}', '${LONGFORM_SNAPSHOT_SECTION_ID}', '${encoded}'::jsonb);
|
|
-- Late ensure and conflicting completion must preserve the first committed snapshot.
|
|
select status from public.ensure_personal_report_section('${USER_A}', '${REQUEST_ID}', '${LONGFORM_SNAPSHOT_SECTION_ID}', 2);
|
|
select status from public.complete_personal_report_section('${USER_A}', '${REQUEST_ID}', '${LONGFORM_SNAPSHOT_SECTION_ID}', '{"kind":"stale-worker"}'::jsonb);
|
|
`));
|
|
const durable = JSON.parse(fixture.psqlScriptAs("postgres", "postgres-test-password", `select payload from public.personal_report_sections where user_id = '${USER_A}' and request_id = '${REQUEST_ID}' and section_id = '${LONGFORM_SNAPSHOT_SECTION_ID}'`));
|
|
assert.deepEqual(validateLongformSnapshot(durable, identity), snapshot);
|
|
assert.equal(fixture.psqlAs("app_runtime", "app-runtime-test-password", selectAsAuthenticated(USER_B, `select count(*) from public.personal_report_sections where section_id = '${LONGFORM_SNAPSHOT_SECTION_ID}'`)), `SET\n${USER_B}\n0`);
|
|
} finally {
|
|
fixture.stop();
|
|
}
|
|
});
|