mirror of
https://github.com/mauriceboe/TREK.git
synced 2026-10-19 13:36:48 +00:00
724c88c201
A mechanical prettier --write over server/src, server/tests, server/scripts and shared/src with the workspaces' .prettierrc; nothing but layout and import order changes, and every file keeps the same set of imports. shared is formatted throughout and its format baseline is empty. The server baseline keeps the 35 files that Prettier would grow past their lint:size limit (they need a split first, which is not a formatting change), and the generated entity files stay as their generator writes them.
146 lines
6.7 KiB
TypeScript
146 lines
6.7 KiB
TypeScript
/**
|
|
* The Postgres probe's ratchet (scripts/pg-probe/baseline.ts). The probe
|
|
* itself only runs in CI against a Postgres service, so the rules that decide
|
|
* whether that job passes are pinned here: a method may not fail more
|
|
* statements than its entry, a stale entry fails until it is lowered, a
|
|
* method the probe did not measure must be listed as uncovered and the list
|
|
* only shrinks, only SQL errors count, an unmeasured baseline has nothing to
|
|
* compare (the run fails on it, see report.test.ts), and --update never
|
|
* raises or adds.
|
|
*/
|
|
import {
|
|
compareWithBaseline,
|
|
countsTowardRatchet,
|
|
formatBaseline,
|
|
lowerBaseline,
|
|
parseBaseline,
|
|
} from '../../../../scripts/pg-probe/baseline';
|
|
|
|
import { readFileSync } from 'node:fs';
|
|
import path from 'node:path';
|
|
import { describe, expect, it } from 'vitest';
|
|
|
|
const now = (entries: Record<string, number>): Map<string, number> => new Map(Object.entries(entries));
|
|
const none = new Set<string>();
|
|
|
|
describe('pg-probe baseline', () => {
|
|
it('PGPROBE-001: parses a measured and an unmeasured baseline; a missing uncovered list reads as unmeasured', () => {
|
|
expect(parseBaseline('{"failing": null, "uncovered": null}', 'b.json')).toEqual({ failing: null, uncovered: null });
|
|
expect(parseBaseline('{"failing": null}', 'b.json')).toEqual({ failing: null, uncovered: null });
|
|
expect(parseBaseline('{"failing": {"TagsRepository.listByUser": 2}, "uncovered": ["A.b"]}', 'b.json')).toEqual({
|
|
failing: { 'TagsRepository.listByUser': 2 },
|
|
uncovered: ['A.b'],
|
|
});
|
|
expect(parseBaseline('{"failing": {}}', 'b.json')).toEqual({ failing: {}, uncovered: null });
|
|
});
|
|
|
|
it('PGPROBE-002: refuses a malformed baseline instead of reading it as empty', () => {
|
|
expect(() => parseBaseline('nope', 'b.json')).toThrow(/b.json is not valid JSON/);
|
|
expect(() => parseBaseline('{}', 'b.json')).toThrow(/"failing" key/);
|
|
expect(() => parseBaseline('[]', 'b.json')).toThrow(/"failing" key/);
|
|
expect(() => parseBaseline('{"failing": []}', 'b.json')).toThrow(/null or an object/);
|
|
expect(() => parseBaseline('{"failing": {"listByUser": 1}}', 'b.json')).toThrow(/not a Class.method key/);
|
|
expect(() => parseBaseline('{"failing": {"A.b": 0}}', 'b.json')).toThrow(/expected a positive integer/);
|
|
expect(() => parseBaseline('{"failing": {"A.b": 1.5}}', 'b.json')).toThrow(/expected a positive integer/);
|
|
expect(() => parseBaseline('{"failing": {}, "uncovered": {}}', 'b.json')).toThrow(
|
|
/"uncovered" must be null or an array/,
|
|
);
|
|
expect(() => parseBaseline('{"failing": {}, "uncovered": ["nodot"]}', 'b.json')).toThrow(
|
|
/expected a Class.method name/,
|
|
);
|
|
expect(() => parseBaseline('{"failing": {}, "uncovered": [1]}', 'b.json')).toThrow(/expected a Class.method name/);
|
|
expect(() => parseBaseline('{"failing": {}, "uncovered": ["A.b", "A.b"]}', 'b.json')).toThrow(/lists A.b twice/);
|
|
});
|
|
|
|
it('PGPROBE-003: an unmeasured baseline (either part null) is flagged instead of compared', () => {
|
|
const flagged = { unseeded: true, grown: [], stale: [], newlyUncovered: [], nowCovered: [] };
|
|
expect(compareWithBaseline({ failing: null, uncovered: null }, now({ 'A.b': 3 }), new Set(['C.d']))).toEqual(
|
|
flagged,
|
|
);
|
|
expect(compareWithBaseline({ failing: { 'A.b': 1 }, uncovered: null }, now({ 'A.b': 3 }), none)).toEqual(flagged);
|
|
expect(compareWithBaseline({ failing: null, uncovered: [] }, now({ 'A.b': 3 }), none)).toEqual(flagged);
|
|
});
|
|
|
|
it('PGPROBE-004: a method failing more statements than its entry (or any without one) fails', () => {
|
|
const verdict = compareWithBaseline(
|
|
{ failing: { 'A.b': 1 }, uncovered: [] },
|
|
now({ 'A.b': 2, 'C.d': 1, 'E.f': 0 }),
|
|
none,
|
|
);
|
|
expect(verdict.grown).toEqual([
|
|
{ method: 'A.b', allowed: 1, now: 2 },
|
|
{ method: 'C.d', allowed: 0, now: 1 },
|
|
]);
|
|
expect(verdict.stale).toEqual([]);
|
|
});
|
|
|
|
it('PGPROBE-005: an entry above what its method fails now is stale, also when the method is gone', () => {
|
|
const verdict = compareWithBaseline(
|
|
{ failing: { 'A.b': 2, 'Gone.away': 1 }, uncovered: [] },
|
|
now({ 'A.b': 1 }),
|
|
none,
|
|
);
|
|
expect(verdict.grown).toEqual([]);
|
|
expect(verdict.stale).toEqual([
|
|
{ method: 'A.b', allowed: 2, now: 1 },
|
|
{ method: 'Gone.away', allowed: 1, now: 0 },
|
|
]);
|
|
});
|
|
|
|
it('PGPROBE-009: a method the probe did not measure must be listed, and a listed method measured now or gone is stale', () => {
|
|
const verdict = compareWithBaseline(
|
|
{ failing: {}, uncovered: ['Kept.out', 'Now.measured', 'Gone.away'] },
|
|
now({ 'Now.measured': 0 }),
|
|
new Set(['Kept.out', 'New.callback', 'Old.throws']),
|
|
);
|
|
expect(verdict).toEqual({
|
|
unseeded: false,
|
|
grown: [],
|
|
stale: [],
|
|
newlyUncovered: ['New.callback', 'Old.throws'],
|
|
nowCovered: ['Gone.away', 'Now.measured'],
|
|
});
|
|
expect(compareWithBaseline({ failing: {}, uncovered: ['A.b'] }, now({}), new Set(['A.b']))).toMatchObject({
|
|
newlyUncovered: [],
|
|
nowCovered: [],
|
|
});
|
|
});
|
|
|
|
it('PGPROBE-006: --update lowers and drops entries but never raises or adds one, in either part', () => {
|
|
const lowered = lowerBaseline(
|
|
{ failing: { 'A.b': 2, 'C.d': 1, 'Gone.away': 1 }, uncovered: ['Kept.out', 'Now.measured'] },
|
|
now({ 'A.b': 1, 'C.d': 5, 'New.one': 3 }),
|
|
new Set(['Kept.out', 'New.callback']),
|
|
);
|
|
expect(lowered).toEqual({ failing: { 'A.b': 1, 'C.d': 1 }, uncovered: ['Kept.out'] });
|
|
});
|
|
|
|
it('PGPROBE-007: the first --update seeds an unmeasured baseline with what fails and what went unmeasured, sorted', () => {
|
|
expect(
|
|
lowerBaseline({ failing: null, uncovered: null }, now({ 'Z.z': 1, 'A.a': 2, 'M.m': 0 }), new Set(['Y.y', 'B.b'])),
|
|
).toEqual({
|
|
failing: { 'A.a': 2, 'Z.z': 1 },
|
|
uncovered: ['B.b', 'Y.y'],
|
|
});
|
|
expect(
|
|
lowerBaseline({ failing: { 'A.a': 3 }, uncovered: null }, now({ 'A.a': 2, 'N.n': 1 }), new Set(['B.b'])),
|
|
).toEqual({
|
|
failing: { 'A.a': 2 },
|
|
uncovered: ['B.b'],
|
|
});
|
|
});
|
|
|
|
it('PGPROBE-010: only syntax and feature errors count toward the ratchet, not data errors from the sample values', () => {
|
|
for (const code of ['42601', '42883', '42804', '42P01', '42703', '0A000'])
|
|
expect(countsTowardRatchet(code)).toBe(true);
|
|
for (const code of ['22P02', '22007', '22008', '23505', '57014', 'NOSQLSTATE'])
|
|
expect(countsTowardRatchet(code)).toBe(false);
|
|
});
|
|
|
|
it('PGPROBE-008: the checked-in baseline parses and formats back to itself', () => {
|
|
const file = path.join(__dirname, '../../../../scripts/pg-probe-baseline.json');
|
|
const text = readFileSync(file, 'utf8');
|
|
expect(formatBaseline(parseBaseline(text, file))).toBe(text.replace(/\r\n/g, '\n'));
|
|
});
|
|
});
|