Files
Cibello-app/apps/worker/test/safety-canary.test.ts
T
Sven (AAMOS AI) 8f20b2ef1b feat(ops): /ops/v1/summary med ai/aktivering/engagemang/betalning/jobb/sakerhet + canary
- Nya toppnivåblock i /ops/v1/summary: ai_scan, aktivering, engagemang,
  betalning, jobb, sakerhet. Alla värden läses från DB/cache; null där data
  saknas, inga påhittade värden.
- AI-kostnad i USD mikrocent (native); intäkter fortsatt SEK-öre.
- product_analytics_events är källa för volym, latens, lyckandegrad,
  felfrekvens, aktivering, retention och engagemang.
- Nya händelser: scan_started (API) och scan_failed/scan_completed med
  latencyMs + felkod (worker). latencyMs flödar nu in i scan_completed.
- Safety canary-jobb varje timme: re-härleder allergener för alla recept,
  räknar överifierade publika recept och food-safety-lint; skriver EN rad till
  ops_safety_canary. Endpointen läser endast sista raden.
- Cache-refresh-jobb var 60 s skriver hela summariet till Redis; endpointen
  serverar cachen med 503 vid cache-miss.
- Bearer-token-skydd med OPS_TOKEN; HTTPS-tvång i produktion; ingen PII.
- Tester för endpoint, auth, cache-miss och safety canary.
2026-08-10 05:47:43 +07:00

36 lines
1.2 KiB
TypeScript

import "./setup-env.js";
import { describe, it, expect, beforeAll, afterAll } from "vitest";
import { createDatabase, schema } from "@app/database";
import { processSafetyCanary } from "../src/processors/safety-canary.js";
import type { WorkerContext } from "../src/context.js";
const testDb = createDatabase(process.env.TEST_DATABASE_URL!);
const ctx: WorkerContext = { db: testDb.db } as never;
describe("RUN_SAFETY_CANARY", () => {
beforeAll(async () => {
await testDb.db.delete(schema.opsSafetyCanary);
});
afterAll(async () => {
await testDb.db.delete(schema.opsSafetyCanary);
await testDb.pool.end();
});
it("re-härleder allergener och skriver en canary-rad", async () => {
const result = await processSafetyCanary(ctx);
expect(typeof result.allergenInvariantBrott).toBe("number");
expect(typeof result.overifieradeVisade).toBe("number");
expect(result.allergenInvariantBrott).toBeGreaterThanOrEqual(0);
const latest = await testDb.db
.select()
.from(schema.opsSafetyCanary)
.orderBy(schema.opsSafetyCanary.occurredAt)
.limit(1);
expect(latest.length).toBe(1);
expect(latest[0]!.allergenInvariantBrott).toBe(result.allergenInvariantBrott);
});
});