Assessor_2.0/tests/features/navigation-performance.test.ts

114 lines
7.1 KiB
TypeScript

import { performance } from 'node:perf_hooks';
import { describe, expect, it, vi } from 'vitest';
import { makeSheet } from '../../src/importers/sheet-factory';
import { genericProfile } from '../../src/profiles/generic/generic-profile';
import { filterAndSortRecords } from '../../src/features/search-filter/filter-records';
import { deriveDynamicFacets, recountFacetsAgainstActiveFilters, type DynamicFacet } from '../../src/features/search-filter/dynamic-facets';
import { summarizeSecurityDomains } from '../../src/features/sidebar/SidebarSecurityDomains';
import { selectWorkFacets } from '../../src/features/search-filter/work-facets';
import type { ImportedDataset } from '../../src/domain/dataset';
import { createSheetDerivationCache } from '../../src/shared/sheet-derivation-cache';
import { defaultReview } from '../../src/domain/review';
describe('navigation derivation performance', () => {
it('measures a repeat Work visit with 8,257 synthetic findings', () => {
const rows = [
['Title', 'Severity', 'Status', 'Category', 'Source: Scan', ...Array.from({ length: 20 }, (_, i) => `Detail ${i}`)],
...Array.from({ length: 8257 }, (_, i) => [
`Synthetic finding ${i}`, ['Critical', 'High', 'Medium', 'Low', 'Info'][i % 5],
i % 3 ? 'Failed' : 'Passed', `Category ${i % 8}`, `Synthetic scan ${i % 4}`,
...Array.from({ length: 20 }, (_, j) => `Synthetic evidence ${j} for record ${i}`)
])
];
const sheet = makeSheet('Synthetic navigation', rows, '', 'synthetic.csv');
const options = { activeProfile: genericProfile, dataset: null, reviews: {}, statusFilter: 'deviation',
facetFilters: {}, search: '', actionOnly: false, sortColumn: 'all', sortDirection: 'desc' as const };
const visit = () => {
const records = filterAndSortRecords(sheet, options);
selectWorkFacets(sheet, options);
const summary = summarizeSecurityDomains({ ...options, sheet });
expect(records).toHaveLength(5504);
expect(summary?.domains.reduce((sum, domain) => sum + domain.count, 0)).toBe(records.length);
};
const first = performance.now();
visit();
const warm = performance.now();
let reads = 0;
for (const record of sheet.analysis.records) {
const fields = record.fields;
Object.defineProperty(record, 'fields', { get: () => { reads += 1; return fields; } });
}
const repeated = performance.now();
visit();
expect(reads).toBe(0);
console.info(JSON.stringify({ syntheticRecords: 8257, coldMs: Math.round(warm - first), warmMs: Math.round(performance.now() - repeated), repeatedFieldReads: reads }));
}, 20_000);
it('invalidates projections for reviews, filters, scopes, profiles and replacement sheets', () => {
const sheet = makeSheet('Synthetic', [['Title', 'Severity', 'Status'],
['One', 'High', 'Failed'], ['Two', 'Low', 'Passed'], ['Three', 'Critical', 'Failed']], '', 'synthetic.csv');
const [one, two, three] = sheet.analysis.records;
const options = { activeProfile: genericProfile, dataset: null, reviews: {}, statusFilter: 'deviation',
facetFilters: {}, search: '', actionOnly: false, sortColumn: 'all', sortDirection: 'desc' as const };
const first = filterAndSortRecords(sheet, options);
expect(first.map(record => record.id)).toEqual([three.id, one.id]);
expect(filterAndSortRecords(sheet, { ...options, facetFilters: {} })).toBe(first);
expect(selectWorkFacets(sheet, { ...options })).toBe(selectWorkFacets(sheet, options));
expect(filterAndSortRecords(sheet, { ...options, statusFilter: 'passed' })).toEqual([two]);
expect(filterAndSortRecords(sheet, { ...options, pathFindingIds: [one.id] })).toEqual([one]);
expect(filterAndSortRecords(sheet, { ...options, search: 'three' })).toEqual([three]);
const reviews = { [one.id]: { ...defaultReview(), include: true } };
expect(filterAndSortRecords(sheet, { ...options, reviews, actionOnly: true })).toEqual([one]);
expect(filterAndSortRecords(sheet, { ...options, reviews: {}, actionOnly: true })).toEqual([]);
const facets = selectWorkFacets(sheet, options);
const severity = facets.find(facet => facet.severityScale)!;
expect(filterAndSortRecords(sheet, { ...options, facetFilters: { [severity.id]: { values: ['high'] } } })).toEqual([one]);
const alternative = { ...genericProfile, matchesStatus: () => false };
expect(filterAndSortRecords(sheet, { ...options, activeProfile: alternative })).toEqual([]);
expect(deriveDynamicFacets(sheet, null, alternative, options.reviews).find(facet => facet.source === 'profile-status')?.values).toEqual([]);
const replacement = { ...sheet, analysis: { ...sheet.analysis, records: [two] } };
expect(filterAndSortRecords(replacement, options)).toEqual([]);
expect(sheet.analysis.records).toEqual([one, two, three]);
});
it('binds workspace source facets to the dataset as well as the active sheet', () => {
const sheet = makeSheet('Synthetic', [['Title', 'Status'], ['One', 'Failed']], '', 'synthetic.csv');
const reviews = {};
const dataset = { sheets: [sheet], scanTool: 'Synthetic A' } as ImportedDataset;
const source = (value: ImportedDataset) => deriveDynamicFacets(sheet, value, genericProfile, reviews)
.find(facet => facet.id === 'provenance:source-scan')?.values[0].label;
expect(source(dataset)).toBe('Synthetic A');
expect(source({ ...dataset, scanTool: 'Synthetic B' })).toBe('Synthetic B');
});
it('bounds retained query variants and evicts the least recently used entry', () => {
const sheet = makeSheet('Synthetic', [['Title'], ['One']], '', 'synthetic.csv');
const cache = createSheetDerivationCache<object>(2);
const first = cache(sheet, ['one'], () => ({}));
cache(sheet, ['two'], () => ({}));
expect(cache(sheet, ['one'], () => ({}))).toBe(first);
cache(sheet, ['three'], () => ({}));
cache(sheet, ['two'], () => ({}));
expect(cache(sheet, ['one'], () => ({}))).not.toBe(first);
});
it('counts self-excluding alternatives with only one active-status check per record', () => {
const sheet = makeSheet('Synthetic', [['Title', 'Category', 'Target', 'Status'],
['One', 'A', 'X', 'Failed'], ['Two', 'A', 'Y', 'Failed'],
['Three', 'B', 'X', 'Failed'], ['Four', 'B', 'Y', 'Passed']], '', 'synthetic.csv');
const facets: DynamicFacet[] = [
{ id: 'category', label: 'Category', kind: 'category', source: 'field', columnIndex: 1,
values: ['a', 'b'].map(value => ({ value, label: value, count: 2 })) },
{ id: 'target', label: 'Target', kind: 'category', source: 'field', columnIndex: 2,
values: ['x', 'y'].map(value => ({ value, label: value, count: 2 })) }
];
const matchesStatus = vi.fn(genericProfile.matchesStatus);
const counts = recountFacetsAgainstActiveFilters({ facets, records: sheet.analysis.records,
filters: { category: { values: ['a'] }, target: { values: ['x'] } }, reviews: {},
statusFilter: 'deviation', matchesStatus });
expect(counts.map(facet => facet.values.map(value => [value.value, value.count])))
.toEqual([[['a', 1], ['b', 1]], [['x', 1], ['y', 1]]]);
expect(matchesStatus.mock.calls.length).toBeLessThanOrEqual(sheet.analysis.records.length);
});
});