Files
Jyotisha/frontend/tests/database-personal-report-jobs.test.ts
T
2026-08-15 05:10:37 +08:00

403 lines
15 KiB
TypeScript

import assert from "node:assert/strict";
import { readFileSync } from "node:fs";
import { spawnSync } from "node:child_process";
import test from "node:test";
import { startPostgresFixture } from "./helpers/postgres-fixture.ts";
const runnerPath = new URL("../scripts/db-migrate.mjs", import.meta.url).pathname;
const jobMigration = readFileSync(
new URL("../db/migrations/20260814040000_personal_report_jobs_v2.sql", import.meta.url),
"utf8",
);
const USER_ID = "aaaaaaaa-aaaa-4aaa-8aaa-aaaaaaaaaaaa";
const REPORT_ID = "bbbbbbbb-bbbb-4bbb-8bbb-bbbbbbbbbbbb";
const REQUEST_ID = "cccccccc-cccc-4ccc-8ccc-cccccccccccc";
const SECOND_REPORT_ID = "dddddddd-dddd-4ddd-8ddd-dddddddddddd";
const SECOND_REQUEST_ID = "eeeeeeee-eeee-4eee-8eee-eeeeeeeeeeee";
const THIRD_REPORT_ID = "77777777-7777-4777-8777-777777777777";
const THIRD_REQUEST_ID = "88888888-8888-4888-8888-888888888888";
const FOURTH_REPORT_ID = "99999999-9999-4999-8999-999999999999";
const FOURTH_REQUEST_ID = "12121212-1212-4121-8121-121212121212";
const FIFTH_REPORT_ID = "34343434-3434-4343-8343-343434343434";
const FIFTH_REQUEST_ID = "56565656-5656-4565-8565-565656565656";
const WRONG_LEASE = "ffffffff-ffff-4fff-8fff-ffffffffffff";
const FINGERPRINT = "1".repeat(64);
const SECOND_FINGERPRINT = "2".repeat(64);
const THIRD_FINGERPRINT = "7".repeat(64);
const FOURTH_FINGERPRINT = "8".repeat(64);
const FIFTH_FINGERPRINT = "9".repeat(64);
const CALCULATION_HASH = "3".repeat(64);
const EVIDENCE_HASH = "4".repeat(64);
const SKILL_NAME = "jyotish-personal-report";
const SKILL_VERSION = "1.0.0";
const SKILL_COMMIT = "5".repeat(40);
const SKILL_SNAPSHOT = "6".repeat(64);
function sqlLiteral(value: string): string {
return `'${value.replaceAll("'", "''")}'`;
}
function documentFor(reportId: string): string {
return JSON.stringify({
schemaVersion: "report_document.v2",
reportId,
provenance: {
calculationHash: CALCULATION_HASH,
evidenceHash: EVIDENCE_HASH,
skillName: SKILL_NAME,
skillVersion: SKILL_VERSION,
skillSourceCommit: SKILL_COMMIT,
skillSnapshotSha256: SKILL_SNAPSHOT,
},
});
}
function insertGeneratingReport(reportId: string, requestId: string, fingerprint: string): string {
return `
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 (
'${reportId}', '${USER_ID}', '${requestId}', '${fingerprint}',
'personal_full', 'generating', 'report_document.v2', 'default',
array['general']::text[], 'standard', '${SKILL_NAME}', '${SKILL_VERSION}',
'${SKILL_COMMIT}', '${SKILL_SNAPSHOT}'
);
`;
}
function completeSql(input: {
jobId: string;
leaseToken: string;
reportId: string;
requestId: string;
fingerprint: string;
}): string {
return `
set role service_role;
select status
from public.complete_personal_report_job(
'${input.jobId}', '${input.leaseToken}', '${USER_ID}', '${input.reportId}',
'${input.requestId}', '${input.fingerprint}', 'report_document.v2',
${sqlLiteral(documentFor(input.reportId))}::jsonb,
'${CALCULATION_HASH}', '${EVIDENCE_HASH}', '${SKILL_NAME}',
'${SKILL_VERSION}', '${SKILL_COMMIT}', '${SKILL_SNAPSHOT}'
);
`;
}
function failSql(input: {
jobId: string;
leaseToken: string;
reportId: string;
requestId: string;
fingerprint: string;
}): string {
return `
set role service_role;
select status
from public.fail_personal_report_job(
'${input.jobId}', '${input.leaseToken}', '${USER_ID}', '${input.reportId}',
'${input.requestId}', '${input.fingerprint}',
'report_schema_invalid', 'report_schema_invalid'
);
`;
}
test("personal report job migration is atomic, lease-bound, recoverable, and owner read-only", () => {
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 20260814025000_personal_report_document_v2\.sql/);
assert.match(migration.stdout, /applied 20260814040000_personal_report_jobs_v2\.sql/);
fixture.psql(`
insert into identity.users (id, name, email, email_verified, email_verified_at)
values ('${USER_ID}', 'Report Test User', 'report-job-test@example.com', true, now());
${insertGeneratingReport(REPORT_ID, REQUEST_ID, FINGERPRINT)}
`);
const originalJobId = fixture.psql(`
select id from public.personal_report_jobs
where user_id = '${USER_ID}' and request_id = '${REQUEST_ID}'
`);
assert.match(originalJobId, /^[0-9a-f-]{36}$/);
// Simulate a generating row created before the durable trigger existed,
// then re-run the forward migration to verify its historical backfill.
fixture.psql(`delete from public.personal_report_jobs where id = '${originalJobId}'`);
assert.equal(fixture.psql(`select count(*) from public.personal_report_jobs where id = '${originalJobId}'`), "0");
fixture.psql(jobMigration);
const backfilledJobId = fixture.psql(`
select id from public.personal_report_jobs
where user_id = '${USER_ID}' and request_id = '${REQUEST_ID}'
`);
assert.match(backfilledJobId, /^[0-9a-f-]{36}$/);
assert.throws(
() => fixture.psqlAs(
"app_runtime",
"app-runtime-test-password",
`set role authenticated;
select set_config('request.jwt.claim.sub', '${USER_ID}', true);
delete from public.personal_report_jobs where id = '${backfilledJobId}';`,
),
/permission denied for table personal_report_jobs/,
);
assert.equal(fixture.psql(`select count(*) from public.personal_report_jobs where id = '${backfilledJobId}'`), "1");
const claim = fixture.psqlAs(
"service_runtime",
"service-runtime-test-password",
`set role service_role;
select id::text || ':' || lease_token::text
from public.claim_personal_report_job('report-worker', 60, '${backfilledJobId}');`,
);
const [jobId, leaseToken] = claim.split("\n").at(-1)!.split(":");
assert.equal(jobId, backfilledJobId);
assert.match(leaseToken, /^[0-9a-f-]{36}$/);
assert.throws(
() => fixture.psqlAs(
"service_runtime",
"service-runtime-test-password",
completeSql({
jobId,
leaseToken: WRONG_LEASE,
reportId: REPORT_ID,
requestId: REQUEST_ID,
fingerprint: FINGERPRINT,
}),
),
/personal_report_job_lease_lost/,
);
assert.equal(
fixture.psql(`
select report.status || ':' || job.status
from public.personal_reports report
join public.personal_report_jobs job
on job.user_id = report.user_id and job.request_id = report.request_id
where report.id = '${REPORT_ID}'
`),
"generating:running",
);
assert.equal(
fixture.psqlAs(
"service_runtime",
"service-runtime-test-password",
completeSql({
jobId,
leaseToken,
reportId: REPORT_ID,
requestId: REQUEST_ID,
fingerprint: FINGERPRINT,
}),
),
"SET\nready",
);
assert.equal(
fixture.psql(`
select report.status || ':' || job.status || ':' || job.progress_percent
from public.personal_reports report
join public.personal_report_jobs job
on job.user_id = report.user_id and job.request_id = report.request_id
where report.id = '${REPORT_ID}'
`),
"ready:ready:100",
);
fixture.psql(insertGeneratingReport(THIRD_REPORT_ID, THIRD_REQUEST_ID, THIRD_FINGERPRINT));
const thirdJobId = fixture.psql(`
select id from public.personal_report_jobs
where user_id = '${USER_ID}' and request_id = '${THIRD_REQUEST_ID}'
`);
const thirdClaim = fixture.psqlAs(
"service_runtime",
"service-runtime-test-password",
`set role service_role;
select lease_token from public.claim_personal_report_job('failure-worker', 60, '${thirdJobId}');`,
);
const thirdLeaseToken = thirdClaim.split("\n").at(-1)!;
assert.match(thirdLeaseToken, /^[0-9a-f-]{36}$/);
assert.throws(
() => fixture.psqlAs(
"service_runtime",
"service-runtime-test-password",
failSql({
jobId: thirdJobId,
leaseToken: WRONG_LEASE,
reportId: THIRD_REPORT_ID,
requestId: THIRD_REQUEST_ID,
fingerprint: THIRD_FINGERPRINT,
}),
),
/personal_report_job_lease_lost/,
);
assert.equal(
fixture.psql(`
select report.status || ':' || job.status
from public.personal_reports report
join public.personal_report_jobs job
on job.user_id = report.user_id and job.request_id = report.request_id
where report.id = '${THIRD_REPORT_ID}'
`),
"generating:running",
);
assert.equal(
fixture.psqlAs(
"service_runtime",
"service-runtime-test-password",
failSql({
jobId: thirdJobId,
leaseToken: thirdLeaseToken,
reportId: THIRD_REPORT_ID,
requestId: THIRD_REQUEST_ID,
fingerprint: THIRD_FINGERPRINT,
}),
),
"SET\nfailed",
);
assert.equal(
fixture.psql(`
select report.status || ':' || report.failure_code || ':'
|| job.status || ':' || job.last_error_code
from public.personal_reports report
join public.personal_report_jobs job
on job.user_id = report.user_id and job.request_id = report.request_id
where report.id = '${THIRD_REPORT_ID}'
`),
"failed:report_schema_invalid:failed:report_schema_invalid",
);
fixture.psql(insertGeneratingReport(SECOND_REPORT_ID, SECOND_REQUEST_ID, SECOND_FINGERPRINT));
const secondJobId = fixture.psql(`
select id from public.personal_report_jobs
where user_id = '${USER_ID}' and request_id = '${SECOND_REQUEST_ID}'
`);
fixture.psql(`
delete from public.personal_report_jobs where id = '${secondJobId}';
insert into public.personal_report_jobs (
id, user_id, request_id, request_fingerprint, status,
attempt_count, max_attempts, next_attempt_at, progress_phase,
last_error_code, last_error_at
) values (
'${secondJobId}', '${USER_ID}', '${SECOND_REQUEST_ID}', '${SECOND_FINGERPRINT}',
'retrying', 2, 3, clock_timestamp() - interval '1 second', 'retry_wait',
'lease_expired', clock_timestamp()
);
`);
const secondClaim = fixture.psqlAs(
"service_runtime",
"service-runtime-test-password",
`set role service_role;
select lease_token from public.claim_personal_report_job('split-worker', 60, '${secondJobId}');`,
);
assert.match(secondClaim.split("\n").at(-1)!, /^[0-9a-f-]{36}$/);
fixture.psql(`
update public.personal_reports
set status = 'ready',
report_document = ${sqlLiteral(documentFor(SECOND_REPORT_ID))}::jsonb,
calculation_hash = '${CALCULATION_HASH}',
evidence_hash = '${EVIDENCE_HASH}',
completed_at = clock_timestamp()
where id = '${SECOND_REPORT_ID}';
update public.personal_report_jobs
set lease_acquired_at = clock_timestamp() - interval '3 seconds',
heartbeat_at = clock_timestamp() - interval '2 seconds',
lease_expires_at = clock_timestamp() - interval '1 second'
where id = '${secondJobId}';
`);
assert.equal(
fixture.psqlAs(
"service_runtime",
"service-runtime-test-password",
"set role service_role; select * from public.recover_expired_personal_report_jobs(10);",
),
"SET\n0|0",
);
assert.equal(
fixture.psql(`select status || ':' || progress_percent from public.personal_report_jobs where id = '${secondJobId}'`),
"ready:100",
);
fixture.psql(insertGeneratingReport(FOURTH_REPORT_ID, FOURTH_REQUEST_ID, FOURTH_FINGERPRINT));
const fourthJobId = fixture.psql(`
select id from public.personal_report_jobs
where user_id = '${USER_ID}' and request_id = '${FOURTH_REQUEST_ID}'
`);
fixture.psql(`
delete from public.personal_report_jobs where id = '${fourthJobId}';
insert into public.personal_report_jobs (
id, user_id, request_id, request_fingerprint, status,
attempt_count, max_attempts, next_attempt_at, progress_phase,
last_error_code, last_error_at
) values (
'${fourthJobId}', '${USER_ID}', '${FOURTH_REQUEST_ID}', '${FOURTH_FINGERPRINT}',
'retrying', 2, 3, clock_timestamp() - interval '1 second', 'retry_wait',
'lease_expired', clock_timestamp()
);
`);
const fourthClaim = fixture.psqlAs(
"service_runtime",
"service-runtime-test-password",
`set role service_role;
select lease_token from public.claim_personal_report_job('exhausted-worker', 60, '${fourthJobId}');`,
);
assert.match(fourthClaim.split("\n").at(-1)!, /^[0-9a-f-]{36}$/);
fixture.psql(`
update public.personal_report_jobs
set lease_acquired_at = clock_timestamp() - interval '3 seconds',
heartbeat_at = clock_timestamp() - interval '2 seconds',
lease_expires_at = clock_timestamp() - interval '1 second'
where id = '${fourthJobId}';
`);
assert.equal(
fixture.psqlAs(
"service_runtime",
"service-runtime-test-password",
"set role service_role; select * from public.recover_expired_personal_report_jobs(10);",
),
"SET\n0|1",
);
assert.equal(
fixture.psql(`
select report.status || ':' || report.failure_code || ':'
|| job.status || ':' || job.last_error_code
from public.personal_reports report
join public.personal_report_jobs job
on job.user_id = report.user_id and job.request_id = report.request_id
where report.id = '${FOURTH_REPORT_ID}'
`),
"failed:calculation_unavailable:failed:lease_expired_attempts_exhausted",
);
fixture.psql(insertGeneratingReport(FIFTH_REPORT_ID, FIFTH_REQUEST_ID, FIFTH_FINGERPRINT));
assert.equal(
fixture.psql(`
select report.status || ':' || job.status
from public.personal_reports report
join public.personal_report_jobs job
on job.user_id = report.user_id and job.request_id = report.request_id
where report.id = '${FIFTH_REPORT_ID}'
`),
"generating:queued",
);
} finally {
fixture.stop();
}
});