import { describe, test, expect } from "bun:test"; import { computeCacheTTL, TTL_HIGH_ACTIVITY, TTL_MODERATE_ACTIVITY, TTL_LOW_ACTIVITY, } from "../../src/modules/algorithms/computeCacheTTL"; // --------------------------------------------------------------------------- // Helpers // --------------------------------------------------------------------------- /** Fixed reference point so tests are deterministic. */ const NOW = new Date("2026-03-02T12:00:00Z"); /** Return a Date offset from NOW by `days` (negative = past, positive = future). */ const daysFromNow = (days: number): Date => new Date(NOW.getTime() + days * 24 * 60 * 60 * 1000); // --------------------------------------------------------------------------- // Rule 1a — Closed records older than 30 days should not be cached // --------------------------------------------------------------------------- describe("computeCacheTTL — Rule 1a: Closed records (>30 days)", () => { test("returns null when closedFlag is true and closedDate is null", () => { expect( computeCacheTTL({ closedFlag: true, closedDate: null, expectedCloseDate: null, lastUpdated: null, now: NOW, }), ).toBeNull(); }); test("returns null when closedFlag is true and closedDate is 60 days ago", () => { expect( computeCacheTTL({ closedFlag: true, closedDate: daysFromNow(-60), expectedCloseDate: daysFromNow(-1), lastUpdated: daysFromNow(-1), now: NOW, }), ).toBeNull(); }); test("returns null when closedFlag is true and closedDate is 31 days ago", () => { expect( computeCacheTTL({ closedFlag: true, closedDate: new Date(NOW.getTime() - 31 * 24 * 60 * 60 * 1000), expectedCloseDate: daysFromNow(2), lastUpdated: null, now: NOW, }), ).toBeNull(); }); }); // --------------------------------------------------------------------------- // Rule 1b — Recently closed (within 30 days) → 15 minutes // --------------------------------------------------------------------------- describe("computeCacheTTL — Rule 1b: Recently closed (≤30 days)", () => { test("returns 15min when closed 1 day ago", () => { expect( computeCacheTTL({ closedFlag: true, closedDate: daysFromNow(-1), expectedCloseDate: null, lastUpdated: null, now: NOW, }), ).toBe(TTL_LOW_ACTIVITY); }); test("returns 15min when closed 15 days ago", () => { expect( computeCacheTTL({ closedFlag: true, closedDate: daysFromNow(-15), expectedCloseDate: null, lastUpdated: null, now: NOW, }), ).toBe(TTL_LOW_ACTIVITY); }); test("returns 15min when closed exactly 30 days ago", () => { expect( computeCacheTTL({ closedFlag: true, closedDate: daysFromNow(-30), expectedCloseDate: null, lastUpdated: null, now: NOW, }), ).toBe(TTL_LOW_ACTIVITY); }); test("returns 15min when closed today even with recent activity dates", () => { expect( computeCacheTTL({ closedFlag: true, closedDate: NOW, expectedCloseDate: daysFromNow(-1), lastUpdated: NOW, now: NOW, }), ).toBe(TTL_LOW_ACTIVITY); }); test("just past 30-day boundary returns null", () => { const justPast30Days = new Date( NOW.getTime() - 30 * 24 * 60 * 60 * 1000 - 1, ); expect( computeCacheTTL({ closedFlag: true, closedDate: justPast30Days, expectedCloseDate: null, lastUpdated: null, now: NOW, }), ).toBeNull(); }); }); // --------------------------------------------------------------------------- // Rule 2 — High activity (within 5 days) → 30 seconds // --------------------------------------------------------------------------- describe("computeCacheTTL — Rule 2: High activity (≤5 days)", () => { test("returns 30s when lastUpdated is today", () => { expect( computeCacheTTL({ closedFlag: false, closedDate: null, expectedCloseDate: null, lastUpdated: NOW, now: NOW, }), ).toBe(TTL_HIGH_ACTIVITY); }); test("returns 30s when lastUpdated is 3 days ago", () => { expect( computeCacheTTL({ closedFlag: false, closedDate: null, expectedCloseDate: null, lastUpdated: daysFromNow(-3), now: NOW, }), ).toBe(TTL_HIGH_ACTIVITY); }); test("returns 30s when lastUpdated is exactly 5 days ago", () => { expect( computeCacheTTL({ closedFlag: false, closedDate: null, expectedCloseDate: null, lastUpdated: daysFromNow(-5), now: NOW, }), ).toBe(TTL_HIGH_ACTIVITY); }); test("returns 30s when expectedCloseDate is 2 days in the future", () => { expect( computeCacheTTL({ closedFlag: false, closedDate: null, expectedCloseDate: daysFromNow(2), lastUpdated: null, now: NOW, }), ).toBe(TTL_HIGH_ACTIVITY); }); test("returns 30s when expectedCloseDate is 5 days in the future", () => { expect( computeCacheTTL({ closedFlag: false, closedDate: null, expectedCloseDate: daysFromNow(5), lastUpdated: null, now: NOW, }), ).toBe(TTL_HIGH_ACTIVITY); }); test("returns 30s when expectedCloseDate is 4 days ago (recently passed)", () => { expect( computeCacheTTL({ closedFlag: false, closedDate: null, expectedCloseDate: daysFromNow(-4), lastUpdated: null, now: NOW, }), ).toBe(TTL_HIGH_ACTIVITY); }); test("returns 30s when either date is within 5 days (lastUpdated wins)", () => { expect( computeCacheTTL({ closedFlag: false, closedDate: null, expectedCloseDate: daysFromNow(-30), lastUpdated: daysFromNow(-2), now: NOW, }), ).toBe(TTL_HIGH_ACTIVITY); }); test("returns 30s when either date is within 5 days (expectedCloseDate wins)", () => { expect( computeCacheTTL({ closedFlag: false, closedDate: null, expectedCloseDate: daysFromNow(3), lastUpdated: daysFromNow(-30), now: NOW, }), ).toBe(TTL_HIGH_ACTIVITY); }); }); // --------------------------------------------------------------------------- // Rule 3 — Moderate activity (within 14 days but > 5 days) → 60 seconds // --------------------------------------------------------------------------- describe("computeCacheTTL — Rule 3: Moderate activity (6–14 days)", () => { test("returns 60s when lastUpdated is 6 days ago", () => { expect( computeCacheTTL({ closedFlag: false, closedDate: null, expectedCloseDate: null, lastUpdated: daysFromNow(-6), now: NOW, }), ).toBe(TTL_MODERATE_ACTIVITY); }); test("returns 60s when lastUpdated is 10 days ago", () => { expect( computeCacheTTL({ closedFlag: false, closedDate: null, expectedCloseDate: null, lastUpdated: daysFromNow(-10), now: NOW, }), ).toBe(TTL_MODERATE_ACTIVITY); }); test("returns 60s when lastUpdated is exactly 14 days ago", () => { expect( computeCacheTTL({ closedFlag: false, closedDate: null, expectedCloseDate: null, lastUpdated: daysFromNow(-14), now: NOW, }), ).toBe(TTL_MODERATE_ACTIVITY); }); test("returns 60s when expectedCloseDate is 8 days in the future", () => { expect( computeCacheTTL({ closedFlag: false, closedDate: null, expectedCloseDate: daysFromNow(8), lastUpdated: null, now: NOW, }), ).toBe(TTL_MODERATE_ACTIVITY); }); test("returns 60s when expectedCloseDate is 14 days in the future", () => { expect( computeCacheTTL({ closedFlag: false, closedDate: null, expectedCloseDate: daysFromNow(14), lastUpdated: null, now: NOW, }), ).toBe(TTL_MODERATE_ACTIVITY); }); test("returns 60s when expectedCloseDate is 12 days ago", () => { expect( computeCacheTTL({ closedFlag: false, closedDate: null, expectedCloseDate: daysFromNow(-12), lastUpdated: null, now: NOW, }), ).toBe(TTL_MODERATE_ACTIVITY); }); }); // --------------------------------------------------------------------------- // Rule 4 — Low activity (older than 14 days) → 15 minutes // --------------------------------------------------------------------------- describe("computeCacheTTL — Rule 4: Low activity (>14 days)", () => { test("returns 15min when lastUpdated is 15 days ago", () => { expect( computeCacheTTL({ closedFlag: false, closedDate: null, expectedCloseDate: null, lastUpdated: daysFromNow(-15), now: NOW, }), ).toBe(TTL_LOW_ACTIVITY); }); test("returns 15min when lastUpdated is 60 days ago", () => { expect( computeCacheTTL({ closedFlag: false, closedDate: null, expectedCloseDate: null, lastUpdated: daysFromNow(-60), now: NOW, }), ).toBe(TTL_LOW_ACTIVITY); }); test("returns 15min when expectedCloseDate is 20 days in the future", () => { expect( computeCacheTTL({ closedFlag: false, closedDate: null, expectedCloseDate: daysFromNow(20), lastUpdated: null, now: NOW, }), ).toBe(TTL_LOW_ACTIVITY); }); test("returns 15min when both dates are null", () => { expect( computeCacheTTL({ closedFlag: false, closedDate: null, expectedCloseDate: null, lastUpdated: null, now: NOW, }), ).toBe(TTL_LOW_ACTIVITY); }); test("returns 15min when both dates are far in the past", () => { expect( computeCacheTTL({ closedFlag: false, closedDate: null, expectedCloseDate: daysFromNow(-100), lastUpdated: daysFromNow(-90), now: NOW, }), ).toBe(TTL_LOW_ACTIVITY); }); }); // --------------------------------------------------------------------------- // Edge cases // --------------------------------------------------------------------------- describe("computeCacheTTL — edge cases", () => { test("defaults `now` to current time when omitted", () => { // Open, no dates → should return LOW_ACTIVITY (15min) const result = computeCacheTTL({ closedFlag: false, closedDate: null, expectedCloseDate: null, lastUpdated: null, }); expect(result).toBe(TTL_LOW_ACTIVITY); }); test("5-day boundary is inclusive", () => { // Exactly 5 days should match high activity expect( computeCacheTTL({ closedFlag: false, closedDate: null, expectedCloseDate: null, lastUpdated: daysFromNow(-5), now: NOW, }), ).toBe(TTL_HIGH_ACTIVITY); }); test("just past 5-day boundary falls to moderate", () => { // 5 days + 1 millisecond past → moderate const justPast5Days = new Date(NOW.getTime() - 5 * 24 * 60 * 60 * 1000 - 1); expect( computeCacheTTL({ closedFlag: false, closedDate: null, expectedCloseDate: null, lastUpdated: justPast5Days, now: NOW, }), ).toBe(TTL_MODERATE_ACTIVITY); }); test("14-day boundary is inclusive", () => { expect( computeCacheTTL({ closedFlag: false, closedDate: null, expectedCloseDate: null, lastUpdated: daysFromNow(-14), now: NOW, }), ).toBe(TTL_MODERATE_ACTIVITY); }); test("just past 14-day boundary falls to low activity", () => { const justPast14Days = new Date( NOW.getTime() - 14 * 24 * 60 * 60 * 1000 - 1, ); expect( computeCacheTTL({ closedFlag: false, closedDate: null, expectedCloseDate: null, lastUpdated: justPast14Days, now: NOW, }), ).toBe(TTL_LOW_ACTIVITY); }); test("higher-priority rule wins when both dates span different tiers", () => { // expectedCloseDate in 5-day window, lastUpdated in 14-day window → 30s expect( computeCacheTTL({ closedFlag: false, closedDate: null, expectedCloseDate: daysFromNow(3), lastUpdated: daysFromNow(-10), now: NOW, }), ).toBe(TTL_HIGH_ACTIVITY); }); test("closed >30 days always returns null regardless of other dates", () => { expect( computeCacheTTL({ closedFlag: true, closedDate: daysFromNow(-60), expectedCloseDate: NOW, lastUpdated: NOW, now: NOW, }), ).toBeNull(); }); test("recently closed always returns 15min regardless of activity dates", () => { expect( computeCacheTTL({ closedFlag: true, closedDate: daysFromNow(-5), expectedCloseDate: NOW, lastUpdated: NOW, now: NOW, }), ).toBe(TTL_LOW_ACTIVITY); }); });