Assessor_2.0/tests/postgres/risk-acceptance-transaction...

36 lines
2.3 KiB
TypeScript

import type { Pool } from 'pg';
import { describe, expect, it } from 'vitest';
import type { FindingReview } from '../../src/domain/canonical-model';
import { PostgresAssessorRepository } from '../../server/postgres/postgres-assessor-repository';
import { riskCommand } from '../domain/risk-acceptance-fixture';
describe('PostgreSQL risk decision transaction', () => {
it('locks the scoped occurrence, appends JSON history and rolls back conflicts', async () => {
const statements: string[] = [];
let review: FindingReview | undefined;
let revision = 0;
const query = async (sql: string, values: unknown[] = []) => {
statements.push(sql);
if (sql.startsWith('SELECT revision FROM assessor_repository_state')) return { rows: [{ revision }], rowCount: 1 };
if (sql.startsWith('UPDATE assessor_repository_state')) return { rows: [{ revision: ++revision }], rowCount: 1 };
if (sql.startsWith('SELECT o.id')) return { rows: [{ id: 'occurrence' }], rowCount: 1 };
if (sql.startsWith('SELECT data FROM assessor_reviews')) return { rows: review ? [{ data: structuredClone(review) }] : [], rowCount: review ? 1 : 0 };
if (sql.startsWith('INSERT INTO assessor_reviews')) { review = JSON.parse(values[4] as string) as FindingReview; return { rows: [], rowCount: 1 }; }
return { rows: [], rowCount: 0 };
};
const pool = { query, connect: async () => ({ query, release() {} }) } as unknown as Pool;
const repository = await PostgresAssessorRepository.create(pool);
const accepted = await repository.recordRiskAcceptance('project', 'occurrence', riskCommand(), 0);
expect(accepted).toEqual(review);
expect(statements.some(sql => sql.includes('a.project_id=$2 FOR UPDATE OF o'))).toBe(true);
expect(statements.at(-1)).toBe('COMMIT');
const previous = structuredClone(review);
await expect(repository.recordRiskAcceptance('project', 'occurrence', riskCommand('revoke'), 0)).rejects.toThrow();
expect(statements.at(-1)).toBe('ROLLBACK');
expect(review).toEqual(previous);
const revoked = await repository.recordRiskAcceptance('project', 'occurrence', riskCommand('revoke'), 1);
expect(revoked.riskAcceptance?.revisions).toHaveLength(2);
expect(revoked.riskAcceptance?.revisions[0]).toEqual(accepted.riskAcceptance?.revisions[0]);
});
});