88 lines
3.4 KiB
TypeScript
88 lines
3.4 KiB
TypeScript
import { describe, expect, it, vi } from 'vitest';
|
|
import type { UnifiedResultProjection } from '../../src/domain/unified-result';
|
|
import {
|
|
buildUnifiedResultJsonl,
|
|
queryAllUnifiedResults,
|
|
RESULT_DB_JSONL_FORMAT,
|
|
RESULT_DB_JSONL_SCHEMA_VERSION,
|
|
unifiedResultJsonlFileName
|
|
} from '../../src/exports/unified-result-jsonl';
|
|
|
|
function result(id: string): UnifiedResultProjection {
|
|
return {
|
|
resultProjectionId: id,
|
|
sourceKind: 'scanner-finding',
|
|
sourceResultId: `source-${id}`,
|
|
projectId: 'project-1',
|
|
assessmentId: 'assessment-1',
|
|
collectionRunId: 'scan-1',
|
|
scanRunId: 'scan-1',
|
|
title: `Synthetic result ${id}`,
|
|
severityOriginal: 'high',
|
|
severityNormalized: 'high',
|
|
outcomeOriginal: 'fail',
|
|
outcomeNormalized: 'fail',
|
|
technicalExecutionState: 'completed',
|
|
resultType: 'compliance_check',
|
|
isIoe: false,
|
|
isDeviation: true,
|
|
lifecycleState: 'unknown',
|
|
mappingConfidence: 1,
|
|
reviewStatus: 'unreviewed',
|
|
importedAt: '2026-09-03T10:00:00.000Z',
|
|
createdAt: '2026-09-03T10:00:00.000Z',
|
|
categories: []
|
|
};
|
|
}
|
|
|
|
describe('filtered Result DB JSONL export', () => {
|
|
it('writes an explicit manifest followed by one complete JSON object per filtered result', () => {
|
|
const text = buildUnifiedResultJsonl({
|
|
projectId: 'project-1', scanRunIds: ['scan-1'], deviation: true,
|
|
severity: ['critical', 'high'], search: 'synthetic', offset: 50, limit: 50
|
|
}, [result('result-1'), result('result-2')], '2026-09-03T12:34:56.789Z');
|
|
const lines = text.trimEnd().split('\n').map(line => JSON.parse(line));
|
|
|
|
expect(lines[0]).toEqual({
|
|
recordType: 'manifest',
|
|
format: RESULT_DB_JSONL_FORMAT,
|
|
schemaVersion: RESULT_DB_JSONL_SCHEMA_VERSION,
|
|
generatedAt: '2026-09-03T12:34:56.789Z',
|
|
resultCount: 2,
|
|
scope: { projectId: 'project-1', scanRunIds: ['scan-1'] },
|
|
filters: { deviation: true, severity: ['critical', 'high'], search: 'synthetic' }
|
|
});
|
|
expect(lines.slice(1)).toEqual([
|
|
{ recordType: 'result', position: 1, result: result('result-1') },
|
|
{ recordType: 'result', position: 2, result: result('result-2') }
|
|
]);
|
|
expect(text.endsWith('\n')).toBe(true);
|
|
expect(unifiedResultJsonlFileName('2026-09-03T12:34:56.789Z'))
|
|
.toBe('assessor-result-db-filtered-2026-09-03T12-34-56Z.jsonl');
|
|
});
|
|
|
|
it('loads every filtered page with the same scope and rejects a changing result set', async () => {
|
|
const all = [result('result-1'), result('result-2'), result('result-3')];
|
|
const reader = vi.fn(async query => ({
|
|
total: all.length,
|
|
items: all.slice(query.offset ?? 0, (query.offset ?? 0) + (query.limit ?? all.length))
|
|
}));
|
|
|
|
await expect(queryAllUnifiedResults(reader, {
|
|
projectId: 'project-1', scanRunIds: ['scan-1'], deviation: true, offset: 99, limit: 1
|
|
}, 2)).resolves.toEqual(all);
|
|
expect(reader).toHaveBeenNthCalledWith(1, {
|
|
projectId: 'project-1', scanRunIds: ['scan-1'], deviation: true, offset: 0, limit: 2
|
|
});
|
|
expect(reader).toHaveBeenNthCalledWith(2, {
|
|
projectId: 'project-1', scanRunIds: ['scan-1'], deviation: true, offset: 2, limit: 2
|
|
});
|
|
|
|
let call = 0;
|
|
await expect(queryAllUnifiedResults(async query => {
|
|
call += 1;
|
|
return { total: call === 1 ? 2 : 3, items: [result(`result-${query.offset ?? 0}`)] };
|
|
}, { deviation: true }, 1)).rejects.toThrow('changed during export');
|
|
});
|
|
});
|