36 lines
2.3 KiB
TypeScript
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]);
|
|
});
|
|
});
|