84 lines
3.3 KiB
TypeScript
84 lines
3.3 KiB
TypeScript
/**
|
|
* Unit tests for the internal-state getters the /metrics endpoint reads.
|
|
* These modules are db-free, so they run under `bun test` (metrics.ts itself
|
|
* transitively imports db.ts / better-sqlite3 and can't be unit-tested here).
|
|
*/
|
|
import { test, expect, describe, beforeEach } from 'bun:test';
|
|
import { getJobStats, createJob, completeJob, failJob, getJob, appendLine, cancelJob } from '../src/lib/server/jobs';
|
|
import { getVulnerabilitiesCacheStats, aggregateCache, inflight } from '../src/lib/server/vulnerabilities-cache';
|
|
|
|
describe('getJobStats', () => {
|
|
test('counts jobs by status', () => {
|
|
const before = getJobStats();
|
|
const a = createJob(); // running
|
|
const b = createJob(); completeJob(b, {}); // done
|
|
const c = createJob(); failJob(c, 'boom'); // error
|
|
const after = getJobStats();
|
|
expect(after.running).toBe(before.running + 1);
|
|
expect(after.done).toBe(before.done + 1);
|
|
expect(after.error).toBe(before.error + 1);
|
|
expect(after.total).toBe(after.running + after.done + after.error);
|
|
void a;
|
|
});
|
|
});
|
|
|
|
describe('job store lifecycle', () => {
|
|
test('createJob starts a running job with an id, empty lines, and timestamps', () => {
|
|
const j = createJob();
|
|
expect(j.id).toBeTruthy();
|
|
expect(j.status).toBe('running');
|
|
expect(j.lines).toEqual([]);
|
|
expect(j.createdAt).toBeGreaterThan(0);
|
|
expect(getJob(j.id)).toBe(j);
|
|
});
|
|
test('getJob returns undefined for an unknown id', () => {
|
|
expect(getJob('does-not-exist')).toBeUndefined();
|
|
});
|
|
test('appendLine pushes progress lines onto the job', () => {
|
|
const j = createJob();
|
|
appendLine(j, { event: 'progress', data: { pct: 10 } });
|
|
appendLine(j, { event: 'progress', data: { pct: 20 } });
|
|
expect(j.lines.length).toBe(2);
|
|
expect(j.lines[1].data).toEqual({ pct: 20 });
|
|
});
|
|
test('completeJob marks done and stores the result', () => {
|
|
const j = createJob();
|
|
completeJob(j, { ok: true });
|
|
expect(j.status).toBe('done');
|
|
expect(j.result).toEqual({ ok: true });
|
|
});
|
|
test('failJob marks error and stores a {success:false,error} result', () => {
|
|
const j = createJob();
|
|
failJob(j, 'boom');
|
|
expect(j.status).toBe('error');
|
|
expect(j.result).toEqual({ success: false, error: 'boom' });
|
|
});
|
|
test('cancelJob cancels a running job (true) but not a terminal or unknown one (false)', () => {
|
|
const running = createJob();
|
|
expect(cancelJob(running.id)).toBe(true);
|
|
|
|
const done = createJob();
|
|
completeJob(done, {});
|
|
expect(cancelJob(done.id)).toBe(false); // already terminal
|
|
|
|
expect(cancelJob('nope')).toBe(false); // unknown id
|
|
});
|
|
});
|
|
|
|
describe('getVulnerabilitiesCacheStats', () => {
|
|
beforeEach(() => { aggregateCache.clear(); inflight.clear(); });
|
|
|
|
test('reports zero for an empty cache', () => {
|
|
expect(getVulnerabilitiesCacheStats()).toEqual({ envs: 0, views: 0, inflight: 0 });
|
|
});
|
|
|
|
test('counts environments, memoized views, and in-flight aggregations', () => {
|
|
const emptySummary = { total: 0, critical: 0, high: 0, medium: 0, low: 0, imagesScanned: 0, totalImages: 0 };
|
|
aggregateCache.set(1, { at: 0, data: { findings: [], summary: emptySummary }, views: new Map([['a', []], ['b', []]]) });
|
|
aggregateCache.set(2, { at: 0, data: { findings: [], summary: emptySummary }, views: new Map([['c', []]]) });
|
|
inflight.set(3, Promise.resolve({ findings: [], summary: emptySummary }));
|
|
|
|
expect(getVulnerabilitiesCacheStats()).toEqual({ envs: 2, views: 3, inflight: 1 });
|
|
});
|
|
});
|