package store import ( "log/slog" "os" "testing" "time" ) func TestSessionStore_CreateAndGet(t *testing.T) { logger := slog.New(slog.NewTextHandler(os.Stdout, nil)) store := NewSessionStore(logger) session := &Session{ Email: "test@example.com", ClientID: "client-123", CodeChallenge: "challenge-abc", } store.Create("code-123", session) retrieved, ok := store.Get("code-123") if !ok { t.Fatal("expected to find session") } if retrieved.Email != "test@example.com" { t.Errorf("expected email test@example.com, got %s", retrieved.Email) } if retrieved.CreatedAt.IsZero() { t.Error("expected CreatedAt to be set") } } func TestSessionStore_Delete(t *testing.T) { logger := slog.New(slog.NewTextHandler(os.Stdout, nil)) store := NewSessionStore(logger) session := &Session{Email: "test@example.com"} store.Create("code-123", session) store.Delete("code-123") _, ok := store.Get("code-123") if ok { t.Error("expected session to be deleted") } } func TestSessionStore_Update(t *testing.T) { logger := slog.New(slog.NewTextHandler(os.Stdout, nil)) store := NewSessionStore(logger) session := &Session{ Email: "test@example.com", Nonce: "old-nonce", } store.Create("old-code", session) // Update and re-index ok := store.Update("old-code", "new-code", func(s *Session) { s.Nonce = "new-nonce" }) if !ok { t.Fatal("expected update to succeed") } // Old code should not exist _, ok = store.Get("old-code") if ok { t.Error("expected old code to be removed") } // New code should exist retrieved, ok := store.Get("new-code") if !ok { t.Fatal("expected to find session with new code") } if retrieved.Nonce != "new-nonce" { t.Errorf("expected nonce new-nonce, got %s", retrieved.Nonce) } } func TestSessionStore_UpdateSameCode(t *testing.T) { logger := slog.New(slog.NewTextHandler(os.Stdout, nil)) store := NewSessionStore(logger) session := &Session{ Email: "test@example.com", Nonce: "old-nonce", } store.Create("code-123", session) originalTime := session.CreatedAt time.Sleep(10 * time.Millisecond) // Update without re-indexing store.Update("code-123", "code-123", func(s *Session) { s.Nonce = "new-nonce" }) retrieved, _ := store.Get("code-123") if retrieved.Nonce != "new-nonce" { t.Errorf("expected nonce new-nonce, got %s", retrieved.Nonce) } // CreatedAt should be refreshed if !retrieved.CreatedAt.After(originalTime) { t.Error("expected CreatedAt to be refreshed") } } func TestSessionStore_UpdateNotFound(t *testing.T) { logger := slog.New(slog.NewTextHandler(os.Stdout, nil)) store := NewSessionStore(logger) ok := store.Update("nonexistent", "new-code", func(s *Session) {}) if ok { t.Error("expected update to fail for nonexistent session") } } func TestSessionStore_Cleanup(t *testing.T) { logger := slog.New(slog.NewTextHandler(os.Stdout, nil)) store := NewSessionStore(logger) // Create an expired session session := &Session{Email: "test@example.com"} store.Create("code-123", session) // Manually set CreatedAt to expired time store.mu.Lock() store.sessions["code-123"].CreatedAt = time.Now().Add(-10 * time.Minute) store.mu.Unlock() // Create a valid session validSession := &Session{Email: "valid@example.com"} store.Create("code-456", validSession) // Run cleanup cleaned := store.Cleanup() if cleaned != 1 { t.Errorf("expected 1 session cleaned, got %d", cleaned) } // Expired session should be gone _, ok := store.Get("code-123") if ok { t.Error("expected expired session to be cleaned up") } // Valid session should still exist _, ok = store.Get("code-456") if !ok { t.Error("expected valid session to still exist") } }