package account import ( "testing" "time" "github.com/google/uuid" ) // TestSuspensionActiveAt covers the wall-clock re-evaluation the cache relies on: a permanent // block is always active, a future-dated one is active, a past-dated one is not. func TestSuspensionActiveAt(t *testing.T) { now := time.Date(2026, 6, 14, 12, 0, 0, 0, time.UTC) future := now.Add(time.Hour) past := now.Add(-time.Hour) if !suspensionActiveAt(Suspension{BlockedUntil: nil}, now) { t.Error("a permanent block must be active") } if !suspensionActiveAt(Suspension{BlockedUntil: &future}, now) { t.Error("a future-dated block must be active") } if suspensionActiveAt(Suspension{BlockedUntil: &past}, now) { t.Error("a past-dated block must be inactive") } } // TestSuspensionCache covers the cache primitives: a miss on an empty cache, a hit after put for // both the not-blocked and blocked markers, and a miss after invalidate. func TestSuspensionCache(t *testing.T) { c := newSuspensionCache() id := uuid.New() if _, ok := c.get(id); ok { t.Fatal("empty cache must miss") } c.put(id, suspensionCacheEntry{found: false}) if e, ok := c.get(id); !ok || e.found { t.Fatalf("cached not-blocked entry = (%+v, ok %v), want hit with found=false", e, ok) } c.put(id, suspensionCacheEntry{susp: Suspension{AccountID: id}, found: true}) if e, ok := c.get(id); !ok || !e.found { t.Fatalf("cached blocked entry = (%+v, ok %v), want hit with found=true", e, ok) } c.invalidate(id) if _, ok := c.get(id); ok { t.Fatal("invalidated entry must miss") } }