import test from "node:test"; import assert from "node:assert/strict"; import { readFileSync } from "node:fs"; import { resolve } from "node:path"; const route = readFileSync(resolve("src/app/api/admin/usage/aggregate/route.ts"), "utf8"); const listRoute = readFileSync(resolve("src/app/api/admin/usage/route.ts"), "utf8"); const simulator = readFileSync(resolve("src/components/admin/pricing-simulator.tsx"), "utf8"); const usageResource = readFileSync(resolve("src/components/admin/billing-operations-resources.tsx"), "utf8"); test("admin usage aggregate is a read-only 30-day billing report", () => { assert.match(route, /requirePermission\("billing\.orders\.read"\)/); assert.match(route, /interval '30 days'/); assert.match(route, /percentile_cont\(0\.50\)/); assert.match(route, /percentile_cont\(0\.95\)/); assert.match(route, /hasData/); assert.match(route, /report\.full/); assert.doesNotMatch(route, /export async function POST/); }); test("admin usage aggregate exposes cache hit rate from metadata without mixing windows", () => { assert.match(route, /metadata \? 'cache'/); assert.match(route, /readTokens/); assert.match(route, /writeTokens/); assert.match(route, /noCacheTokens/); assert.match(route, /days7/); assert.match(route, /days30/); assert.match(route, /hitRate/); assert.match(route, /cacheShare/); assert.match(route, /make_interval\(days => w\.days\)/); assert.doesNotMatch(route, /create index|alter table public\.usage_ledger/); }); test("admin usage list returns cache read tokens from ledger metadata", () => { assert.match(listRoute, /requirePermission\("billing\.orders\.read"\)/); assert.match(listRoute, /metadata->'cache'->>'readTokens'/); assert.match(listRoute, /cacheReadTokens/); assert.match(usageResource, /缓存读 tokens/); assert.match(simulator, /缓存命中/); });