51 lines
2.6 KiB
TypeScript
51 lines
2.6 KiB
TypeScript
import { describe, expect, it } from 'vitest';
|
|
import type { RegulatoryMappingBatchRun } from '../../src/domain/regulatory-mapping';
|
|
import { LocalAssessorRepository } from '../../src/persistence/local-assessor-repository';
|
|
|
|
const stamp = '2026-09-16T08:00:00.000Z';
|
|
|
|
function batch(overrides: Partial<RegulatoryMappingBatchRun> = {}): RegulatoryMappingBatchRun {
|
|
return {
|
|
version: 1,
|
|
id: 'batch-1',
|
|
projectId: 'project-1',
|
|
scopeKey: 'scope-1',
|
|
filterHash: 'a'.repeat(64),
|
|
idempotencyKey: 'batch-request-1',
|
|
assessmentIds: ['assessment-1'],
|
|
scanRunIds: [],
|
|
filters: { deviation: true },
|
|
status: 'queued',
|
|
counts: {
|
|
filteredResultCount: 0, excludedNonScannerCount: 0, eligibleFindingCount: 0, unsupportedFindingCount: 0,
|
|
distinctRuleCount: 0, reusedSucceededRuleCount: 0, reusedActiveRuleCount: 0, scheduledRuleCount: 0,
|
|
succeededRuleCount: 0, failedRuleCount: 0
|
|
},
|
|
createdAt: stamp,
|
|
updatedAt: stamp,
|
|
...overrides
|
|
};
|
|
}
|
|
|
|
describe('local regulatory mapping batch persistence', () => {
|
|
it('preserves idempotency and active-scope uniqueness, exports batches and deletes them with the project', async () => {
|
|
const repository = new LocalAssessorRepository();
|
|
await repository.saveProject({ id: 'project-1', name: 'Synthetic', createdAt: stamp, updatedAt: stamp, attributes: {} });
|
|
await repository.saveAssessment({ id: 'assessment-1', projectId: 'project-1', name: 'Synthetic', createdAt: stamp, updatedAt: stamp });
|
|
const first = await repository.createRegulatoryMappingBatchRun(batch());
|
|
|
|
await expect(repository.createRegulatoryMappingBatchRun(batch({ id: 'batch-idempotent' }))).resolves.toEqual(first);
|
|
await expect(repository.createRegulatoryMappingBatchRun(batch({ id: 'batch-active', idempotencyKey: 'batch-request-2' }))).resolves.toEqual(first);
|
|
expect((await repository.exportProject('project-1')).regulatoryMappingBatchRuns).toEqual([first]);
|
|
|
|
const running = await repository.updateRegulatoryMappingBatchRun({ ...first, status: 'running', startedAt: stamp });
|
|
await repository.updateRegulatoryMappingBatchRun({ ...running, status: 'completed', completedAt: stamp });
|
|
const retry = await repository.createRegulatoryMappingBatchRun(batch({ id: 'batch-2', idempotencyKey: 'batch-request-2' }));
|
|
expect((await repository.listRegulatoryMappingBatchRuns('project-1', 'scope-1')).map(item => item.id)).toEqual(['batch-2', 'batch-1']);
|
|
expect(retry.id).toBe('batch-2');
|
|
|
|
await repository.deleteProject('project-1', { projectId: 'project-1', cascade: true });
|
|
await expect(repository.listRegulatoryMappingBatchRuns('project-1')).resolves.toEqual([]);
|
|
});
|
|
});
|