Files
CASAN/packages/casan-control-panel/backend/test/telemetry.test.ts
T
2026-07-08 19:07:35 +09:00

89 lines
3.6 KiB
TypeScript

import { test } from 'node:test';
import assert from 'node:assert/strict';
import { existsSync, mkdtempSync, writeFileSync } from 'node:fs';
import { tmpdir } from 'node:os';
import { join } from 'node:path';
import { readJsonl, readJson, readHead } from '../src/telemetry/telemetry.reader.js';
import { APP_ROOT, PATHS, isStale, metricsAgeSeconds } from '../src/common/app-root.js';
import { TelemetryService } from '../src/telemetry/telemetry.service.js';
test('readJsonl parses valid lines and skips malformed', () => {
const d = mkdtempSync(join(tmpdir(), 'cp-'));
const f = join(d, 'x.jsonl');
writeFileSync(f, '{"a":1}\n\nnot-json\n{"a":2}\n');
const rows = readJsonl<{ a: number }>(f);
assert.equal(rows.length, 2);
assert.equal(rows[0].a, 1);
assert.equal(rows[1].a, 2);
});
test('readJsonl/readJson tolerate missing files (no throw)', () => {
assert.deepEqual(readJsonl('/no/such/file.jsonl'), []);
assert.equal(readJson('/no/such/file.json'), null);
assert.equal(readHead('/no/such/head.txt'), null);
});
test('APP_ROOT resolves to the CASAN app root (has a harness marker)', () => {
const marker = existsSync(join(APP_ROOT, 'packages', 'casan-harness')) || existsSync(join(APP_ROOT, '.specify'));
assert.ok(marker, `APP_ROOT=${APP_ROOT} should contain .specify or packages/casan-harness`);
});
test('overview() returns real aggregated shape, never throws on the repo state', () => {
const svc = new TelemetryService();
const o = svc.overview() as any;
assert.ok(o.totals && typeof o.totals.runs === 'number');
assert.ok(o.harness_signals && o.harness_signals['H5-governance']);
assert.ok(o.audit_chain && typeof o.audit_chain.records === 'number');
assert.ok('stale' in o && 'stale_after_s' in o);
// real data: metrics + audit feeds exist in this repo, so counts are non-negative
assert.ok(o.totals.runs >= 0);
assert.ok(o.audit_chain.records >= 0);
});
test('security()/governance()/cost() return objects with expected keys', () => {
const svc = new TelemetryService();
assert.ok(typeof (svc.security() as any).by_status === 'object');
assert.ok(typeof (svc.governance() as any).by_decision === 'object');
assert.ok('provider_tokens' in (svc.cost() as any));
});
test('commandCenter() returns evidence-backed widget contract', () => {
const svc = new TelemetryService();
const command = svc.commandCenter() as any;
const ids = Object.keys(command.widgets);
assert.deepEqual(ids.sort(), [
'certification',
'finops',
'hitl',
'kill_switch',
'maturity',
'security',
'self_improve',
'traceability',
]);
for (const w of Object.values(command.widgets) as any[]) {
assert.ok(w.id && w.title && w.status);
assert.ok(w.envelope && typeof w.envelope.artifact_path === 'string');
assert.ok(['verified', 'present_unverified', 'missing'].includes(w.envelope.status));
assert.equal(typeof w.envelope.verified, 'boolean');
}
assert.ok(Array.isArray(command.briefing));
assert.ok(Array.isArray(command.ticker));
});
test('freshness helpers behave (age is number|null, isStale is boolean)', () => {
const age = metricsAgeSeconds();
assert.ok(age === null || typeof age === 'number');
assert.equal(typeof isStale(), 'boolean');
});
test('missing metrics feed => stale (fail-loud)', () => {
const prev = process.env.CASAN_DASHBOARD_METRICS;
process.env.CASAN_DASHBOARD_METRICS = '/no/such/metrics.jsonl';
// re-import is not trivial (module caches PATHS); assert the reader-level contract instead:
assert.deepEqual(readJsonl('/no/such/metrics.jsonl'), []);
if (prev === undefined) delete process.env.CASAN_DASHBOARD_METRICS;
else process.env.CASAN_DASHBOARD_METRICS = prev;
void PATHS;
});