package session import ( "context" "errors" "testing" "time" ) type fakeResolver struct { uid string err error calls int } func (f *fakeResolver) ResolveSession(_ context.Context, _ string) (string, error) { f.calls++ if f.err != nil { return "", f.err } return f.uid, nil } func TestResolveCachesBackendHit(t *testing.T) { r := &fakeResolver{uid: "user-1"} c := NewCache(r, time.Minute, 10) for i := 0; i < 3; i++ { uid, err := c.Resolve(context.Background(), "tok") if err != nil || uid != "user-1" { t.Fatalf("resolve #%d = (%q, %v)", i, uid, err) } } if r.calls != 1 { t.Fatalf("backend calls = %d, want 1 (cached)", r.calls) } } func TestResolvePropagatesBackendError(t *testing.T) { r := &fakeResolver{err: errors.New("nope")} c := NewCache(r, time.Minute, 10) if _, err := c.Resolve(context.Background(), "tok"); err == nil { t.Fatal("expected backend error to propagate") } } func TestResolveReResolvesAfterTTL(t *testing.T) { r := &fakeResolver{uid: "user-1"} c := NewCache(r, time.Minute, 10) base := time.Now() c.now = func() time.Time { return base } if _, err := c.Resolve(context.Background(), "tok"); err != nil { t.Fatal(err) } c.now = func() time.Time { return base.Add(2 * time.Minute) } // past TTL if _, err := c.Resolve(context.Background(), "tok"); err != nil { t.Fatal(err) } if r.calls != 2 { t.Fatalf("backend calls = %d, want 2 (re-resolve after expiry)", r.calls) } } func TestInvalidateForcesReResolve(t *testing.T) { r := &fakeResolver{uid: "user-1"} c := NewCache(r, time.Minute, 10) _, _ = c.Resolve(context.Background(), "tok") c.Invalidate("tok") _, _ = c.Resolve(context.Background(), "tok") if r.calls != 2 { t.Fatalf("backend calls = %d, want 2 after invalidate", r.calls) } }