log-fanout.test.ts49 lines · main
1/**
2 * Audit-log retention boundary tests — pin the 13-month window so a
3 * tweak to the constant or the math surfaces in CI rather than as a
4 * silent compliance drift (privacy policy §5).
5 *
6 * The DB-touching path (pruneOldAuditLogs) is exercised by the
7 * post-deploy smoke; this file pins the pure cutoff calculation.
8 */
9
10import { describe, expect, test } from 'bun:test';
11
12import { AUDIT_RETENTION_DAYS, auditRetentionCutoff } from './log-fanout.js';
13
14describe('AUDIT_RETENTION_DAYS', () => {
15 test('matches the policy commitment of 13 months (≈ 390 days)', () => {
16 expect(AUDIT_RETENTION_DAYS).toBe(390);
17 });
18});
19
20describe('auditRetentionCutoff', () => {
21 // Fixed point so the deltas are easy to reason about.
22 const NOW = new Date('2026-05-11T00:00:00Z').getTime();
23 const ONE_DAY = 86_400_000;
24
25 test('cutoff is exactly 13 months before now', () => {
26 const cutoff = auditRetentionCutoff(NOW);
27 const deltaDays = Math.round((NOW - cutoff.getTime()) / ONE_DAY);
28 expect(deltaDays).toBe(AUDIT_RETENTION_DAYS);
29 });
30
31 test('cutoff rolls forward with now (no caching surprise)', () => {
32 const cutoff1 = auditRetentionCutoff(NOW);
33 const cutoff2 = auditRetentionCutoff(NOW + 7 * ONE_DAY);
34 expect(cutoff2.getTime() - cutoff1.getTime()).toBe(7 * ONE_DAY);
35 });
36
37 test('a row 13 months + 1 day old is past cutoff', () => {
38 const cutoff = auditRetentionCutoff(NOW);
39 const rowAge = AUDIT_RETENTION_DAYS + 1;
40 const rowCreatedAt = new Date(NOW - rowAge * ONE_DAY);
41 expect(rowCreatedAt.getTime()).toBeLessThan(cutoff.getTime());
42 });
43
44 test('a row 12 months old is still inside the window', () => {
45 const cutoff = auditRetentionCutoff(NOW);
46 const rowCreatedAt = new Date(NOW - 360 * ONE_DAY);
47 expect(rowCreatedAt.getTime()).toBeGreaterThan(cutoff.getTime());
48 });
49});