test: cover uok metrics cache refresh

This commit is contained in:
Mikael Hugo 2026-05-07 04:36:08 +02:00
parent 79896b4377
commit 856ce4d530
2 changed files with 83 additions and 1 deletions

View file

@ -0,0 +1,82 @@
/**
* uok-metrics-exposition.test.mjs Prometheus metrics cache behaviour.
*
* Purpose: prove cached UOK metric snapshots are explicitly refreshable so
* health surfaces can trade scrape cost for freshness without serving stale
* data after known DB writes.
*/
import assert from "node:assert/strict";
import { mkdtempSync, rmSync } from "node:fs";
import { tmpdir } from "node:os";
import { join } from "node:path";
import { afterEach, test } from "vitest";
import { closeDatabase, insertGateRun, openDatabase } from "../sf-db.js";
import {
invalidateMetricsCache,
readUokMetrics,
writeUokMetrics,
} from "../uok/metrics-exposition.js";
const tmpDirs = [];
afterEach(() => {
closeDatabase();
invalidateMetricsCache();
while (tmpDirs.length > 0) {
const dir = tmpDirs.pop();
if (dir) rmSync(dir, { recursive: true, force: true });
}
});
function makeProject() {
const dir = mkdtempSync(join(tmpdir(), "sf-uok-metrics-"));
tmpDirs.push(dir);
openDatabase(":memory:");
return dir;
}
function recordGateRun(outcome, evaluatedAt = new Date().toISOString()) {
insertGateRun({
traceId: `trace-${outcome}`,
turnId: `turn-${outcome}`,
gateId: "cache-gate",
gateType: "verification",
unitType: "execute-task",
unitId: "M001/S01/T01",
milestoneId: "M001",
sliceId: "S01",
taskId: "T01",
outcome,
failureClass: outcome === "pass" ? "" : "assertion",
rationale: outcome,
findings: "",
attempt: 1,
maxAttempts: 1,
retryable: false,
evaluatedAt,
durationMs: outcome === "pass" ? 10 : 20,
});
}
test("writeUokMetrics_when_cache_invalidated_refreshes_db_snapshot", () => {
const project = makeProject();
recordGateRun("pass");
writeUokMetrics(project, ["cache-gate"]);
const first = readUokMetrics(project);
assert.match(first, /uok_gate_runs_total\{gate_id="cache-gate"\} 1/);
recordGateRun("fail");
writeUokMetrics(project, ["cache-gate"]);
const cached = readUokMetrics(project);
assert.match(cached, /uok_gate_runs_total\{gate_id="cache-gate"\} 1/);
invalidateMetricsCache();
writeUokMetrics(project, ["cache-gate"]);
const refreshed = readUokMetrics(project);
assert.match(refreshed, /uok_gate_runs_total\{gate_id="cache-gate"\} 2/);
assert.match(
refreshed,
/uok_gate_runs_failed_total\{gate_id="cache-gate"\} 1/,
);
});

View file

@ -99,7 +99,7 @@ function collectGateMetrics(gateIds) {
return lines;
}
function buildMetricsText(gateIds) {
export function buildMetricsText(gateIds) {
const cacheKey = gateIds ? gateIds.join(",") : "";
const now = Date.now();
if (