Files
optima/api/tests/unit/computeCacheTTL.test.ts

478 lines
13 KiB
TypeScript
Raw Permalink Blame History

This file contains ambiguous Unicode characters
This file contains Unicode characters that might be confused with other characters. If you think that this is intentional, you can safely ignore this warning. Use the Escape button to reveal them.
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 (614 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);
});
});