import { AuditLogger, MemoryAuditAdapter } from "@suaveplan/audit-logging"; import { describe, expect, it } from "@suaveplan/testing/runner"; import { Hono } from "hono"; import { createAuditMiddleware } from "../../src/middleware/audit-middleware.js"; import type { AuditPluginConfig } from "../../src/types/types.js"; const noopHostLogger = { debug: () => undefined, info: () => undefined, warn: () => undefined, error: () => undefined, }; /** * Deterministic Mulberry32 RNG so the test is reproducible across * Bun + Node runtime engines. */ function mulberry32(seed: number): () => number { let t = seed >>> 0; return () => { t = (t + 0x6d2b79f5) >>> 0; let r = t; r = Math.imul(r ^ (r >>> 15), r | 1); r ^= r + Math.imul(r ^ (r >>> 7), r | 61); return ((r ^ (r >>> 14)) >>> 0) / 4294967296; }; } describe("sampling integration", () => { it("50% sample rate over 1000 requests sits in [400, 600] band", { timeout: 30000, }, async () => { const storage = new MemoryAuditAdapter(); const logger = new AuditLogger({ storage, secretKey: "x".repeat(32), }); const config: AuditPluginConfig = { sink: storage, secretKey: "x".repeat(32), samplingRate: 0.5, excludePaths: [], redactQueryParams: [], redactHeaders: [], redactBodyFields: [], recordResponseSize: false, recordRequestBody: false, enableChainIntegrity: false, rng: mulberry32(1234567), }; const app = new Hono(); app.use( "*", createAuditMiddleware({ logger, config, hostLogger: noopHostLogger, }) ); app.get("/x", (c) => c.text("ok")); for (let i = 0; i < 1000; i += 1) { await app.request(`/x?i=${i}`); } const count = storage.snapshot().length; expect(count).toBeGreaterThanOrEqual(400); expect(count).toBeLessThanOrEqual(600); }); });